openSIPS setup an onreply route if the call is picked up - sip

I'm wondering if is it possible to set a condition for call answered/picked up in an onreply_route
something like this
onreply_route {
if(call picked up) {
xlog("ON AIR");
}
}

There are quite a few ways in which you can achieve this. For your case, I would use the tm module's t_check_status() function:
onreply_route {
if (t_check_status("2[0-9][0-9]")) {
xlog("ON AIR");
}
}
However, note that this will not work if your SIP proxy is stateless (i.e. if you don't use tm at all)! In this case, we would need to access the information in a more low-level way, by reading it straight off the received message using the $rs variable (SIP reply status):
onreply_route {
if ($rs == 200) { # or ($rs =~ "2[0-9][0-9]")
xlog("ON AIR");
}
}

Related

FastCGI, Perl and Exit

I've been honing the performance a large, decades old codebase I use for projects over the last few weeks and it was suggested to me on here that I should look at something like FastCGI or HTTP::Engine. I've found it impressively straightforward to make use of FastCGI, but there's one nagging question I've found mixed answers on.
Some documents I've read say you should never call exit on a script being run through FastCGI, since that harms the whole concept of keeping it loaded persistently. Others say it doesn’t matter. My code uses exit in a lot of places where it is important to make sure nothing keeps executing. For example, I have restricted access components that call an authorization check:
use MyCode::Authorization;
our $authorization = MyCode::Authorization->new();
sub administration {
$authorization->checkCredentials();
#...Do restricted access stuff.
}
To make it as hard for there to be an error in the code as possible where someone would be permitted to access those functions when they shouldn't, checkCredentials ends the process with exit() after generating a user friendly response with a login page if the answer is that the user does not have the appropriate credentials. E.g.:
sub checkCredentials {
#Logic to check credentials
if ($validCredential) {
return 1;
}
else {
# Build web response.
# Then:
exit;
}
}
}
I’ve used it so that I don’t accidentally overlook something continuing on that causes a security hole. At present, the calling routine can safely assume it only gets back control from checkCredentials if the right credentials are provided.
However, I’m wondering if I need to remove those calls to make good use of FastCGI. Is FCGI's $req->Finish() (or the equivalent in PSGI for HTTP::Engine) an adequate replacement?
I've read say you should never call exit on a script being run through FastCGI,
You don't want the process to exit since the point of using FastCGI is to use a single process to handle multiple requests (to avoid load times, etc).
So you want to do is override exit so that is ends your request-specific code, but not the FastCGI request loop.
You can override exit, but you must do so at compile-time. So use a flag to signal whether the override is active or not.
our $override_exit = 0;
BEGIN {
*CORE::GLOBAL::exit = sub(;$) {
die "EXIT_OVERRIDE\n" if $override_exit;
CORE::exit($_[0] // 0);
};
}
while (get_request()) {
# Other setup...
eval {
local $override_exit = 1;
handle_request();
};
my $exit_was_called = $# eq "EXIT_OVERRIDE\n";
log_error($#) if $# && !$exit_was_called;
log_error("Exit called\n") if $exit_was_called;
# Other cleanup...
}
But that creates an exception that might be caught unintentionally. So let's use last instead.
our $override_exit = 0;
BEGIN {
*CORE::GLOBAL::exit = sub(;$) {
no warnings qw( exiting );
last EXIT_OVERRIDE if $override_exit;
CORE::exit($_[0] // 0);
};
}
while (get_request()) {
# Other setup...
my $exit_was_called = 1;
EXIT_OVERRIDE: {
local $override_exit = 1;
eval { handle_request() };
log_error($#) if $#;
$exit_was_called = 0;
}
log_error("Exit called\n") if $exit_was_called;
# Other cleanup...
}

Vertx: How to verify auth before handle body request?

How to verify auth before handle body request?
I'm using vertx:
vertxVersion = '3.8.3'
implementation "io.vertx:vertx-core:$rootProject.vertxVersion"
implementation "io.vertx:vertx-web:$rootProject.vertxVersion"
implementation "io.vertx:vertx-lang-kotlin:$rootProject.vertxVersion"
implementation "io.vertx:vertx-lang-kotlin-coroutines:$rootProject.vertxVersion"
implementation "io.vertx:vertx-mongo-client:$rootProject.vertxVersion"
implementation "io.vertx:vertx-auth-mongo:$rootProject.vertxVersion"
implementation "io.vertx:vertx-auth-jwt:$rootProject.vertxVersion"
I want to verify auth before handle body request. But I got error java.lang.IllegalStateException: Request has already been read
Reproduce by use delay on suspend function:
router.handler { context ->
launch {
context.request().setExpectMultipart(true)
delay(100) //This line is sample for a verify auth process
context.next()
}
}
.handler {context ->
println("2")
context.request()
.handler {
b -> println("buff ${b.length()}")
}
.endHandler {
println("end handle")
context.success("ok")
}
}.baseHandle(
fn
).failureHandler {
println("fail: ${it.failure()}")
it.error()
}
When run delay(100) (this's sample for a verify process), I got the error above. If I comment delay(100), It's will be working fine.
This happens because by the time you auhenticated the request, the content has kept arriving and has been dropped.
You need to invoke context.request().pause() in you first handler and then context.request().resume() when you're ready.
In most cases though it's easier to let the BodyHandler manage payload for you.
Finally, I did solve it.
My router is working with the flows:
router.post("/api/upload/file")
.baseHandle { checkAuthorization(it) }
.handleFileUpload { updateFileOnItem(it) }
And Following step:
fun checkAuthorization(context: RoutingContext) {
val request = context.request()
val tkCookie = request.getCookie("user")
...do something to verify user permission
request.pause()
context.next()
context.request().resume()
}
Next:
fun updateFileOnItem(context: RoutingContext) {
val file = context.fileUploads()
...do something
}
It's working with me. Hope it can be help you. Thanks!

Read large file using vertx

I am new to using vertx and I am using vertx filesystem api to read file of large size.
vertx.fileSystem().readFile("target/classes/readme.txt", result -> {
if (result.succeeded()) {
System.out.println(result.result());
} else {
System.err.println("Oh oh ..." + result.cause());
}
});
But the RAM is all consumed while reading and the resource is not even flushed after use. The vertx filesystem api also suggest
Do not use this method to read very large files or you risk running out of available RAM.
Is there any alternative to this?
To read large file you should open an AsyncFile:
OpenOptions options = new OpenOptions();
fileSystem.open("myfile.txt", options, res -> {
if (res.succeeded()) {
AsyncFile file = res.result();
} else {
// Something went wrong!
}
});
Then an AsyncFile is a ReadStream so you can use it together with a Pump to copy the bits to a WriteStream:
Pump.pump(file, output).start();
file.endHandler((r) -> {
System.out.println("Copy done");
});
There are different kind of WriteStream, like AsyncFile, net sockets, HTTP server responses, ...etc.
To read/process a large file in chunks you need to use the open() method which will return an AsyncFile on success. On this AsyncFile you setReadBufferSize() (or not, the default is 8192), and attach a handler() which will be passed a Buffer of at most the size of the read buffer you just set.
In the example below I have also attached an endHandler() to print a final newline to stay in line with the sample code you provided in the question:
vertx.fileSystem().open("target/classes/readme.txt", new OpenOptions().setWrite(false).setCreate(false), result -> {
if (result.succeeded()) {
result.result().setReadBufferSize(READ_BUFFER_SIZE).handler(data -> System.out.print(data.toString()))
.endHandler(v -> System.out.println());
} else {
System.err.println("Oh oh ..." + result.cause());
}
});
You need to define READ_BUFFER_SIZE somewhere of course.
The reason for that is that internally .readFile calls to Files.readAllBytes.
What you should do instead is create a stream out of your file, and pass it to Vertx handler:
try (InputStream steam = new FileInputStream("target/classes/readme.txt")) {
// Your handling here
}

Unlang write to file FreeRADIUS

I know I might be facing an impossible mission. What I do want is radiusd to write down every mac received in an Acces-Request, for later on deny access to those MAC.
I know the policies file is written in unlang, bad news are that radiusd does not have any write permissions on any of the conf files...
Anyway, was anyone capable of WRITTING to a file in the POLICY PROCESSING of FreeRADIUS?
What I want to achieve would be something like this:
raddb/sites-available/default
authorize {
rewrite_calling_station_id
unauthorized_macs
if(ok) {
reject
}
else {
update control {
Auth-Type := Accept
}
GET MAC FROM CALLIN_STATION_ID ATTRIBUTE
WRITE THIS F***ING MAC TO unauthorized_macs FILE
}
}
Thanks to Arran, I could solve this the following way:
authorize {
rewrite_calling_station_id
authMac
if(ok) {
reject
}
else {
linelog
update control {
Auth-Type := Accept
}
}
}
Where linelog is configured as follows:
raddb/mods-enabled/linelog
linelog {
filename = /path/to/hell/authMac
format = "%{Calling-Station-ID}"
}
update request {
Tmp-String-0 := `echo "%{Calling-Station-ID}" >> "/path/to/f___ing_unauthorized_macs_file"`
}
There's also the linelog module which would be better in >= v3.0.x as it implements internal locking (in addition to flock) to prevent line interleaving.
See /etc/raddb/mods-available/linelog for examples.

Raising events in KRL without using explicit

I'm writing an app that raises events, similar to how Phil Windley's personal data manager application works. However, if I try to use any event domain but explicit, the events don't get propagated. The following rules work fine with explicit as the domain, but not with driverreg.
rule driver_info_submit {
select when web pageview ".*"
pre {
driver_name = "Joe Driver";
driver_phone = "111-555-1212";
msg = <<
Current driver info: #{ent:driver_name}, #{ent:driver_phone}
>>;
}
notify("Started", msg);
fired {
raise explicit event new_driver_data with driver_name=driver_name and driver_phone=driver_phone;
}
}
// Save driver name
rule save_driver_name {
select when explicit new_driver_data
pre {
driver_name = event:param("driver_name") || ent:driver_name;
driver_phone = event:param("driver_phone") || ent:driver_phone;
}
noop();
always {
set ent:driver_name driver_name;
set ent:driver_phone driver_phone;
raise explicit event driver_data_updated;
}
}
rule driver_info_updated {
select when explicit driver_data_updated
{
notify("Driver name", ent:driver_name);
notify("Driver phone", ent:driver_phone);
}
}
It doesn't seem to be a problem with whether the app is deployed, as I've tried it both ways. What am I missing?
Only certain domains are allowed as domains in the raise statement:
explicit
http
system
notification
error
pds
This may be relaxed in the future.
This is covered in the documents here: https://kynetxdoc.atlassian.net/wiki/display/docs/Raising+Explicit+Events+in+the+Postlude
(note that this is a temporary home for the documentation)