how to make kamailio serial forking? - kamailio

######################################################################################
I am a beginner in kamailio server development, and I want to make serial forking, but that doesn't work.
My kamailio server replies Too Many Hops (code: 483) and end the call.
can someone helps me please.
######################################################################################
I use this code :
request_route {
# per request initial checks
route(REQINIT);
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans()) {
t_relay();
}
exit;
}
# handle retransmissions
if (!is_method("ACK")) {
if(t_precheck_trans()) {
t_check_trans();
exit;
}
t_check_trans();
}
if (is_method("INVITE|SUBSCRIBE")) {
record_route();
}
if(is_method("REGISTER"))
save("location");
# test serial forking
if (method=="INVITE") {
if(!t_is_set("branch_route")) route(SERIAL);
};
if(lookup("location")){
if (!t_relay()) {
sl_reply_error();
}
exit;
}
}
route[SERIAL]{
$ru = "sip:1001#192.168.50.131:5060";
xlog("ALERT : new request uri $ru \n");
t_on_failure("1");
t_relay();
}
failure_route[1] {
if(t_is_canceled()) {
exit;
}
xlog(" an other alternative \n");
if(t_check_status("486|408")){
$ru = "sip:1002#192.168.50.131:5060";
xlog(" an other uri $ru \n");
t_on_failure("2");
t_relay();
exit;
}
}
failure_route[2] {
if(t_is_canceled()) {
exit;
}
xlog( "nobody available \n");
t_reply("500", "Server error");
}
# Per SIP request initial checks
route[REQINIT] {
# no connect for sending replies
set_reply_no_connect();
#!ifdef WITH_ANTIFLOOD
# flood detection from same IP and traffic ban for a while
# be sure you exclude checking trusted peers, such as pstn gateways
# - local host excluded (e.g., loop to self)
if(src_ip!=myself) {
if($sht(ipban=>$si)!=$null) {
# ip is already blocked
xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
exit;
}
if (!pike_check_req()) {
xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
$sht(ipban=>$si) = 1;
exit;
}
}
#!endif
if($ua =~ "friendly-scanner|sipcli|sipvicious|VaxSIPUserAgent") {
# silent drop for scanners - uncomment next line if want to reply
# sl_send_reply("200", "OK");
exit;
}
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
}
if(is_method("OPTIONS") && uri==myself && $rU==$null) {
sl_send_reply("200","Keepalive");
exit;
}
if(!sanity_check("17895", "7")) {
xlog("Malformed SIP request from $si:$sp\n");
exit;
}
}

Problem is that in your config your serial forking route runs before looking into Kamailio location DB. So after first fork to 1001#192.168.50.131 you need somehow to route call to part where Kamailio looks into location DB, in default config it is route(LOCATION). Something like this:
route[SERIAL]{
$ru = "sip:1001#192.168.50.131:5060";
xlog("ALERT : new request uri $ru \n");
t_on_failure("1");
route(location);
}
Don't forget to add route(location) to your config.

Related

How to parse IP address in P4

I have a basic task to connect some nodes to switch and let them communicate only with even-to-even and odd-to-odd IP addresses.
Scenario topology:
The starting point is an access network with full L2 connectivity based on a <DestMAC,OutputPort> table implemented on P4 switch.
Goal
Write a P4 code that creates two network slices, one enabling communication only between nodes with even IP addresses
and the other enabling communication only between nodes with odd IP addresses
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4; //tay
}
/**SOME CODE*/
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action check_ip_odd_even(){
//TODO:
}
action forward_to_port(bit<9> egress_port) {
standard_metadata.egress_spec = egress_port;
}
table dmac_forward {
key = {
hdr.ethernet.dstAddr: exact;
}
actions = {
//ipv4_forward;
forward_to_port;
drop;
}
size = 8;
default_action = drop;
}
apply {
// if(hdr.ipv4.srcAddr & 1 == 1){
// //it's odd
// //dmac_forward.apply();
// }
// else {
// // it's even
// dmac_forward.apply();
// }
//10.0.0.13 vs 10.0.0.11
if (hdr.ipv4.srcAddr == 0x0a00000D && hdr.ipv4.dstAddr == 0x0a00000b){
dmac_forward.apply();
}
}
}
I tried to and with 1 so if it's 1 I would say it's odd but my solution didn't work. I also tried with exactly given IP addresses but this is not the general solution.
Any suggestion, please?

How to get network connection status in apple watch standalone application?

Using NWPathMonitor, I get network information in watch simulator (with usesInterfaceType) and it showing right status, but in real device it's not working. It alway showing no network. I developed independent watch application. Please check below code that I write for this:
let monitor = NWPathMonitor()
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
print("We're connected!")
if path.usesInterfaceType(.wifi) {
print("It's WiFi!")
} else if path.usesInterfaceType(.cellular) {
print("3G/4G FTW!!!")
} else if path.usesInterfaceType(.wiredEthernet) {
print("wiredEthernet")
}else if path.usesInterfaceType(.loopback) {
print("loopback")
}else if path.usesInterfaceType(.other) {
print("other")
}
}
else {
print("No connection.")
}
}
let queue = DispatchQueue(label: "InternetConnectionMonitor")
monitor.start(queue: queue)

How to reproduce behavior of VCL 3.0 vcl_recv / restart in VCL 4.0

I'm upgrading an old Varnish 3 server to Varnish 6.11
This Varnish server was setup to avoid caching large files (over 100mb) using pipe. The request was first sent normally to the backend and, if the size from the response Content-Length header was over 100mb, the request was retried: vcl_recv was called a second time internally with a new x-pipe header to the request indicating vlc_recv to pipe instead of hash. That was the way to do it back then:
added to vcl_recv:
/* Bypass cache for large files. The x-pipe header is
set in vcl_fetch when a too large file is detected. */
if (req.http.x-pipe && req.restarts > 0) {
remove req.http.x-pipe;
return (pipe);
}
added to vcl_fetch:
# don't cache files larger than 10MB
/* Don't try to cache too large files. It appears
Varnish just crashes if we don't filter them. */
if (beresp.http.Content-Length ~ "[0-9]{8,}" ) {
set req.http.x-pipe = "1";
return (restart);
}
Now that vcl_fetch was changed to vcl_backend_response, the restart action has vanished. Replacing retry with restart doesn't achieve the same behavior as the vcl_recv function is not called a second time. retry only retries the backend request.
Returning pass in vcl_backend_response suffers from the same reason pipe existed: the request will need to be read into memory by Varnish before being sent to client and that's what pipe avoided.
My question is: how to pipe (send the bytes directly from the backend to the client without any processing) large files using VCL 4.0?
It's doable, but things got slightly more complicated since Varnish Cache 4.0 due to the separation between client and backend threads.
The idea is you need to (1) jump form vcl_backend_response to vcl_backend_error; (2) create and return to the client thread a synthetic response (and ideally cache it to avoid request serialization); and (3) check the previous response during vcl_deliver and execute the restart in the client thread. The following test case shows a working example:
varnishtest "..."
server s1 {
rxreq
txresp -hdr "X-Large-Response: 1"
} -repeat 3 -start
varnish v1 -vcl+backend {
sub vcl_recv {
if (req.restarts == 0) {
unset req.http.X-Restart-And-Pipe;
} elsif (req.http.X-Restart-And-Pipe) {
return (pipe);
}
}
sub vcl_deliver {
if (resp.http.X-Restart-And-Pipe) {
set req.http.X-Restart-And-Pipe = "1";
return (restart);
}
}
sub vcl_backend_fetch {
if (bereq.retries == 0) {
unset bereq.http.X-Restart-And-Pipe;
}
}
sub vcl_backend_response {
if (beresp.http.X-Large-Response) {
set bereq.http.X-Restart-And-Pipe = "1";
return (error);
} else {
unset beresp.http.X-Restart-And-Pipe;
}
}
sub vcl_backend_error {
if (bereq.http.X-Restart-And-Pipe) {
set beresp.http.X-Restart-And-Pipe = "1";
set beresp.ttl = 1s;
set beresp.grace = 0s;
set beresp.keep = 0s;
return (deliver);
}
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -run
varnish v1 -expect n_object == 1
varnish v1 -expect sess_conn == 2
varnish v1 -expect client_req == 2
varnish v1 -expect s_sess == 2
varnish v1 -expect s_pipe == 2
Bad news is jumping from vcl_backend_response to vcl_backend_error using return (error) is only possible since Varnish Cache 6.3.0. Using an older version is still possible to do it, but the solution is a little bit hacky: first you need to jump to vcl_backend_fetch and then use an always broken backend:
varnishtest "..."
server s1 {
rxreq
txresp -hdr "X-Large-Response: 1"
} -repeat 3 -start
varnish v1 -vcl+backend {
backend always_broken_be {
.host = "127.0.0.1";
.port = "666";
}
sub vcl_recv {
if (req.restarts == 0) {
unset req.http.X-Restart-And-Pipe;
} elsif (req.http.X-Restart-And-Pipe) {
return (pipe);
}
}
sub vcl_deliver {
if (resp.http.X-Restart-And-Pipe) {
set req.http.X-Restart-And-Pipe = "1";
return (restart);
}
}
sub vcl_backend_fetch {
if (bereq.retries == 0) {
unset bereq.http.X-Restart-And-Pipe;
} elsif (bereq.http.X-Restart-And-Pipe) {
set bereq.backend = always_broken_be;
}
}
sub vcl_backend_response {
if (beresp.http.X-Large-Response) {
set bereq.http.X-Restart-And-Pipe = "1";
return (retry);
} else {
unset beresp.http.X-Restart-And-Pipe;
}
}
sub vcl_backend_error {
if (bereq.http.X-Restart-And-Pipe) {
set beresp.http.X-Restart-And-Pipe = "1";
set beresp.ttl = 1s;
set beresp.grace = 0s;
set beresp.keep = 0s;
return (deliver);
}
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -run
varnish v1 -expect n_object == 1
varnish v1 -expect sess_conn == 2
varnish v1 -expect client_req == 2
varnish v1 -expect s_sess == 2
varnish v1 -expect s_pipe == 2

How to control socket on peer[TCP Hole Punching]

I have a server-client program that use TCP connection to communicate. More than one client can connect to the server at the same time. I want to implement the tcp hole punching on this system.
On the client side, It calls to the public server to look up the public ip,port of my server. Then connect to it.
But on the server side it has to open a port to connect to the public server, and it also has to accept the client connection request on this same port.
What I'm going to do is opening a socket and bind to port X, then connect to the public server, then change this socket to listening state to accept the incoming connection for some period, then start connection to the public server again, over and over.
Is this the right approach ?
EDIT: I have another idea. It is to open a new port and connect to the public server. The main server port is left listening for incoming connection as usual. When the client want to connect, the public server will tell my server via the new port. It will stop the main port from listen the incoming connection, instead, It will connect to the client to do the hole punching. Then It connect to the public server, which will forward the server public ip address to the client, and goes back to listen for incoming connection as usual. The client will then use this address to connect to the server which TCP hole already opened.
Better have two socket and maintain separate the conection between server and client.
m_nServerTCPSocket- used to connect and listner socket with server
m_nPeerPrivateTCPSocket- to connect with peer (public address)
m_nPeerPublicTCPSocket- to connect with peer (private address if other peer is in the same network)
m_nListeningTCPSocket - used to listener socket for peer here u need to accept connection from peer.
m_nConnectedPeerTCPSocket-> you get this socket once you connected with other peer.
while(end_client)
{
FD_ZERO(&fdRead);
FD_ZERO(&fdWrite);
FD_ZERO(&fdExcept);
if (pControlMgr->GetConnectionMgr()->GetListeningTCPSocket()>0)
{
FD_SET (pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),&fdRead);
FD_SET (pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),&fdExcept);
}
if (pControlMgr->GetConnectionMgr()->GetServerTCPSocket()>0)
{
FD_SET (pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),&fdRead);
FD_SET (pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),&fdExcept);
}
if (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket()>0)
{
FD_SET (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),&fdRead);
FD_SET (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),&fdExcept);
}
timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
nSelectRetVal = select(NULL,&fdRead,NULL,&fdExcept,&tv);
if (nSelectRetVal>0)
{
int nRecvRetVal = 0;
/* TCP Server Socket handling */
if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(), &fdRead ))
{
try
{
pRecvBuffer = new char[TCP_RECV_SIZE];
nRecvRetVal = recv(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),
pRecvBuffer,TCP_RECV_SIZE,
0);
int n = WSAGetLastError();
if (nRecvRetVal>0)
{
int nPeerNameRetVal = getpeername(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),(sockaddr*)&addrRemotePeer,&nSockAddrLen);
if ( pControlMgr->HandlePacket(pRecvBuffer,addrRemotePeer)== -1 )
{
if ( NULL != pRecvBuffer)
{
delete [] pRecvBuffer;
pRecvBuffer = NULL;
return 0 ;
}
}
}
}
catch (...)
{
if ( NULL != pRecvBuffer )
{
delete [] pRecvBuffer;
pRecvBuffer = NULL;
}
}
if ( NULL != pRecvBuffer)
{
delete [] pRecvBuffer;
pRecvBuffer = NULL;
}
} /* TCP Server Socket handling */
int n;
/* TCP Exception Server Socket handling */
if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(), &fdExcept ))
{
/*FD_CLR(pControlMgr->GetConnectionMgr().GetServerTCPSocket (),&fdRead);
FD_CLR(pControlMgr->GetConnectionMgr().GetServerTCPSocket (),&fdExcept);*/
n = WSAGetLastError();
//return 0;
}
if (FD_ISSET(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),&fdRead))
{
sockaddr_in addrConnectedPeer;
int nAddrLen =sizeof(addrConnectedPeer) ;
int nConnectedSock = accept( pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),
(sockaddr*)&addrConnectedPeer,
&nAddrLen);
int n1 = WSAGetLastError();
if (nConnectedSock>0)
{
pControlMgr->GetConnectionMgr()->SetConnectedTCPSocket(nConnectedSock);
int n = pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket();
continue;
}
}
/* TCP Exception Listening Socket handling */
if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(), &fdExcept ))
{
FD_CLR(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket (),&fdRead);
FD_CLR(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket (),&fdExcept);
//return 0;
} /* TCP Exception Listening Socket handling */
/* Connected Peer TCP Read Socket handling */
if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(), &fdRead ))
{
try
{
pRecvBuffer = new char[TCP_RECV_SIZE];
nRecvRetVal = recv (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),
pRecvBuffer,TCP_RECV_SIZE,
0);
if (nRecvRetVal>0)
{
int nPeerNameRetVal = getpeername(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),(sockaddr*)&addrRemotePeer,&nSockAddrLen);
if ( pControlMgr->HandlePacket(pRecvBuffer,addrRemotePeer)== -1 )
{
if ( NULL != pRecvBuffer)
{
delete [] pRecvBuffer;
pRecvBuffer = NULL;
return 0 ;
}
}
}
}
catch (...)
{
if ( NULL != pRecvBuffer )
{
delete [] pRecvBuffer;
pRecvBuffer = NULL;
}
}
//FD_CLR(pControlMgr->GetConnectionMgr().GetConnectedTCPSocket(),&fdRead);
if ( NULL != pRecvBuffer)
{
delete [] pRecvBuffer;
pRecvBuffer = NULL;
}
} /* Peer TCP Read Socket handling */
/* TCP Exception Connected Socket handling */
if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(), &fdExcept ))
{
/*FD_CLR(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket (),&fdRead);
FD_CLR(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket (),&fdExcept);
return 0;*/
n = WSAGetLastError();
}
logic to create sockets
int CConnectionMgr::CreateSocket(const int nSockType)
{
//TODO: Add code here
if (InitWinSock() == -1)
{
return -1;
}
SetLocalIPAddress();
m_nListeningTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if ( GetListeningTCPSocket() <0 )
return -1;
if (BindSocket(GetListeningTCPSocket())<0)
return -1;
int nListenRet = listen(GetListeningTCPSocket(),SOMAXCONN);
if (nListenRet!=0)
{
return -1;
}
m_nPeerPrivateTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if (GetPeerPrivateTCPSocket()<0)
return -1;
if (BindSocket(GetPeerPrivateTCPSocket())<0)
return -1;
m_nPeerPublicTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if ( GetPeerPublicTCPSocket()<0)
return -1;
if (BindSocket(GetPeerPublicTCPSocket())<0)
return -1;
m_nServerTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if (GetServerTCPSocket()<0)
return -1;
if (BindSocket(GetServerTCPSocket())<0)
return -1;
return 1;
}

How to retrieve vista's network status (e.g. "Local Only", "Local and Internet") in powershell

I have a flaky NIC that drops out from time to time, especially after resuming from hibernation. A drop-out corresponds to Vista's network status showing in the notification area as "Local Only". Is there a way of retrieving these status values (e.g. "Limited Connectivity", "Local Only", "Local and Internet") programmatically?
I am writing a powershell script that polls to see if the connection is down, and if so, resets the adapter. Currently I am trying to detect the connection state by pinging my ISP's DNS server. However, since the OS is already correctly identifying this condition, it would be much simpler if I could just retrieve this value.
Thanks!
Try this function:
PS> function Get-NetworkStatus {
$t = [Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")
$networkListManager = [Activator]::CreateInstance($t)
$connections = $networkListManager.GetNetworkConnections()
function getconnectivity {
param($network)
switch ($network.GetConnectivity()) {
0x0000 { 'disconnected' }
{ $_ -band 0x0001 } { 'IPV4_NOTRAFFIC' }
{ $_ -band 0x0002 } { 'IPV6_NOTRAFFIC' }
{ $_ -band 0x0010 } { 'IPV4_SUBNET' }
{ $_ -band 0x0020 } { 'IPV4_LOCALNETWORK' }
{ $_ -band 0x0040 } { 'IPV4_INTERNET' }
{ $_ -band 0x0100 } { 'IPV6_SUBNET' }
{ $_ -band 0x0200 } { 'IPV6_LOCALNETWORK' }
{ $_ -band 0x0400 } { 'IPV6_INTERNET' }
}
}
$connections |
% {
$n = $_.GetNetwork();
$name = $n.GetName();
$category = switch($n.GetCategory()) { 0 { 'public' } 1 { 'private' } 2 { 'domain' } }
$connectivity = getConnectivity $n
new-object PsObject -property #{Name=$name; Category=$category; Connectivity=$connectivity }
}
}
PS> Get-NetworkStatus
Name Connectivity Category
---- ------------ --------
Neznámá síť {IPV4_NOTRAFFIC, IPV6_NOTRAFFIC} public
stefan {IPV6_NOTRAFFIC, IPV4_INTERNET} private
If you pipe $connections and output from GetNetwork() to Get-Member you will find some more useful methods.

Resources