sip
19 TopicsBIG-IP for SIP resources running in Kubernetes
Hello, We are trying to setup Virtual Server using BIG-IP that would server as a Load Balancer for SIP traffic for resources that are deployed in Kubernetes cluster and exposed through NodePort. Our F5 is not part of the Kubernetes cluster and it is a standalone Virtual Machine that sends its traffic to NodePort service of our SIP resources. We are facing few issues and hope someone can help us understand them. UDP not working When we try to use UDP the problem is that F5 (10.224.64.223) sends SIP OPTIONS to ip address/port that we defined as access point for SIP elements in Kubernetes (Node IP and NodePort port, 10.224.64.222, port:31131). But due to Kubernetes deployment, responses are sent from different IP address and port (10.224.64.222, port 30834). And this gets rejected by the F5. 10:17:23.695039 IP 10.224.64.223.51938 > 10.224.64.222.31131: UDP, length 575 out slot1/tmm1 lis=mon_mrf_sip_udp port=1.2 trunk= 10:17:23.700849 IP 10.224.64.220.30834 > 10.224.64.223.51938: UDP, length 520 in slot1/tmm0 lis= port=1.2 trunk= 10:17:23.700949 IP 10.224.64.223 > 10.224.64.220: ICMP 10.224.64.223 udp port 51938 unreachable, length 36 out slot1/tmm0 lis= port=1.2 trunk= Even the usage of macvlan on Kubernetes pods does not help. With macvlan we manage to achieve that IP address is preserved (10.226.64.225), but still the port changes (5060 -> 25404). And F5 rejects it. 10:42:07.370926 IP 10.224.64.223.54412 > 10.224.64.225.5060: SIP: OPTIONS sip:10.224.64.225:5060 SIP/2.0 out slot1/tmm0 lis= port=1.2 trunk= 10:42:07.378237 IP 10.224.64.225.25404 > 10.224.64.223.54412: UDP, length 425 in slot1/tmm0 lis= port=1.2 trunk= 10:42:07.378325 IP 10.224.64.223 > 10.224.64.225: ICMP 10.224.64.223 udp port 54412 unreachable, length 36 out slot1/tmm0 lis= port=1.2 trunk= So I guess there is no way to have it working for UDP at all with resources being deployed in Kubernets cluster? (host-network is not an option). TCP (in Message Routing mode) not working When we try to use TCP we found out that "Standard (SIP - legacy profile)" mode behaves differently then "Message Routing" one. In case when we use "Legacy" SIP monitor via TCP it establishes a TCP connection with destination server prior to sending the SIP Options message. This is OK for us. But when we try to use "Message Routing" (from what I understood this is generally advisable for SIP traffic) for TCP monitoring, TCP connection is not established before OPTIONS message is sent and this is not acceptable by our SIP servers. So I have few questions: Is it even possible to use F5 BIG-IP TLM VE as SIP LB for SIP resources operating in Kubernetes cluster (for both UDP and TCP) or the ONLY option is to use F5 BIG-IP Next Service Proxy Kubernetes (SPK) for SIP traffic? Is there a way to somehow force F5 that does Monitoring usin Message Routing mode to open TCP connection prior to sending SIP requests? Due to UDP problem above (that probably is solvable only if SPK version is used) is some way for F5 to do the UDP-2-TCP conversion of SIP traffic? Kind Regards, Zvonimir43Views0likes0CommentsDoS and NTLM Brute force protection for SIP traffic
Problem this snippet solves: This snippet has been designed to mainly protect against NTLM's downgrade attacks present in a widely used Instant Messaging solution. This solution authenticate users on the SIP/TLS protocol. This irule block brute forced users and source IP address. How to use this snippet: This snippet should be applied on the Virtual Server that handle SIP/TLS traffic. SSL bridging is required to make this irule work properly. Moreover, Skype for Business may require that you change your cipher suite to a weak one. The internal domain should be define in " email_domain " and " user_domain " variables. The script will focus on those domains. The max attempts before blocking is defined in the " max_failures " variable. This setting should be under the max attempts allowed on the Active Directory. The blocking duration is configured in the " block_duration " variable. (in seconds) The " fail_memory " variable define the window that we increase the attempt counter. After reaching the end of this duration, the entry is removed until a new invalid attempt occurs. External links Github : github.com/e-XpertSolutions/f5 Related Articles DoS and NTLM Brute force protection for HTTP(s) flow Code : when RULE_INIT { array set NTLMFlags { unicode 0x00000001 oem 0x00000002 req_target 0x00000004 unknown1 0x00000008 sign 0x00000010 seal 0x00000020 datagram 0x00000040 lmkey 0x00000080 netware 0x00000100 ntlm 0x00000200 unknown2 0x00000400 unknown3 0x00000800 ntlm_domain 0x00001000 ntlm_server 0x00002000 ntlm_share 0x00004000 NTLM2 0x00008000 targetinfo 0x00800000 128bit 0x20000000 keyexch 0x40000000 56bit 0x80000000 } set static::email_domain "domain.org" set static::user_domain "DOMAIN" set static::log_pri "local0." set static::fail_tab "NTLMfails" set static::blacklist_tab "NTLMblackhole" set static::userfail_tab "NTLMUserfails" set static::userblacklist_tab "NTLMUserblackhole" set static::max_failures 5 set static::fail_memory 300 set static::block_duration 300 } when CLIENT_ACCEPTED { if {[table lookup -subtable $static::blacklist_tab [IP::client_addr]] == 1} { log $static::log_pri "[virtual] - BLACKHOLED IPADDR [IP::client_addr]:[TCP::client_port] (Reputation=[IP::reputation [IP::client_addr]])" reject return } } when CLIENTSSL_HANDSHAKE { SSL::collect } when CLIENTSSL_DATA { set payload [SSL::payload] if { ($payload contains "3 REGISTER") } { regexp -nocase {gssapi-data=\"([A-Za-z0-9+\/=]*)\",} $payload match gssapi garbage if { [info exists match] } { unset match unset garbage if { $gssapi != "" } { set ntlm_msg [ b64decode [string trim $gssapi]] binary scan $ntlm_msg a7ci protocol zero type if { $type eq 3} { binary scan $ntlm_msg @12ssissississississii \ lmlen lmlen2 lmoff \ ntlen ntlen2 ntoff \ dlen dlen2 doff \ ulen ulen2 uoff \ hlen hlen2 hoff \ slen slen2 soff \ flags set ntlm_domain {}; binary scan $ntlm_msg @${doff}a${dlen} ntlm_domain set ntlm_user {}; binary scan $ntlm_msg @${uoff}a${ulen} ntlm_user set ntlm_host {}; binary scan $ntlm_msg @${hoff}a${hlen} ntlm_host set unicode [expr {$flags & 0x00000001}] if {$unicode} { set ntlm_domain_convert "" foreach i [ split $ntlm_domain ""] { scan $i %c c if {$c>1} { append ntlm_domain_convert $i } elseif {$c<128} { set ntlm_domain_convert $ntlm_domain_convert } else { append ntlm_domain_convert \\u[format %04.4X $c] } } set ntlm_domain $ntlm_domain_convert set ntlm_user_convert "" foreach i [ split $ntlm_user ""] { scan $i %c c if {$c>1} { append ntlm_user_convert $i } elseif {$c<128} { set ntlm_user_convert $ntlm_user_convert } else { append ntlm_user_convert \\u[format %04.4X $c] } } set ntlm_user $ntlm_user_convert set ntlm_host_convert "" foreach i [ split $ntlm_host ""] { scan $i %c c if {$c>1} { append ntlm_host_convert $i } elseif {$c<128} { set ntlm_host_convert $ntlm_host_convert } else { append ntlm_host_convert \\u[format %04.4X $c] } } set ntlm_host $ntlm_host_convert } binary scan $ntlm_msg @${ntoff}a${ntlen} ntdata binary scan $ntlm_msg @${lmoff}a${lmlen} lmdata binary scan $ntdata H* ntdata_h binary scan $lmdata H* lmdata_h set interesting 1 if { ($ntlm_domain equals $static::user_domain or $ntlm_user ends_with $static::email_domain) } { set attack 1 if {[table lookup -subtable $static::userblacklist_tab $ntlm_user] == 1} { log $static::log_pri "[virtual] - BLACKHOLED $ntlm_domain\\$ntlm_user from $ntlm_host at [IP::client_addr]:[TCP::client_port] (Reputation=[IP::reputation [IP::client_addr]])" reject return } else { log $static::log_pri "[virtual] - Login attempt by $ntlm_domain\\$ntlm_user from $ntlm_host for SIP." } } else { set attack 0 log $static::log_pri "[virtual] - Not a valid user - Login attempt by $ntlm_domain\\$ntlm_user from $ntlm_host for SIP." } } } } } # Release the payload SSL::release SSL::collect } when SERVERSSL_HANDSHAKE { SSL::collect SSL::release 0 } when SERVERSSL_DATA { set payload [SSL::payload] if {[info exists interesting] && $interesting == 1} { set client [IP::client_addr]:[TCP::client_port] set node [IP::server_addr]:[TCP::server_port] if { $payload contains "401 Unauthorized ms-user-logon-data" and ([info exists attack] and $attack == 1) } { table set -subtable $static::fail_tab -notouch -excl [IP::client_addr] 0 indef $static::fail_memory table incr -subtable $static::fail_tab [IP::client_addr] set now [clock seconds] set now_date [split [clock format $now -format {%X %x}] " "] set later [expr {$now + $static::block_duration}] set later_date [split [clock format $later -format {%X %x}] " "] if {[info exists ntlm_user]} { table set -subtable $static::userfail_tab -notouch -excl $ntlm_user 0 indef $static::fail_memory table incr -subtable $static::userfail_tab $ntlm_user if {[table lookup -subtable $static::userfail_tab $ntlm_user] >= $static::max_failures} { log $static::log_pri "[virtual] - BLACKHOLING USER - $ntlm_user at $now_date until $later_date" table set -subtable $static::userblacklist_tab -excl $ntlm_user 1 indef $static::block_duration } } if {[table lookup -subtable $static::fail_tab [IP::client_addr]] >= $static::max_failures} { log $static::log_pri "[virtual] - BLACKHOLING IPADDR - [IP::client_addr] (Reputation=[IP::reputation [IP::client_addr]]) at $now_date until $later_date" table set -subtable $static::blacklist_tab -excl [IP::client_addr] 1 indef $static::block_duration } } } SSL::release SSL::collect } Tested this on version: 11.5365Views0likes0CommentsF5 SIP proxy load-balancer handle REGISTRATION
We have F5 base SIP proxy load-balancer and we have 2 server some reason i don't want F5 load-balance REGISTER method between two servers, i want REGISTER packet goes to server1 and INVITE packet goes to server2 but if any one of server fail remaining server take care of both REGISTER/INVITE How do i handle this kind of requirement using iRule?Solved580Views0likes3CommentsSIP irule for checking dialed string
Hi guys, Please help me with creating na irule for checking a dialed string in SIP INVITE request. I need to drop every call that has !=8 or !=0 symbols in the SIP INVITE. Like this: sip:3286184@206.81.166.10 I need to strip only "3286184" portion, then check if it has 8 or 0 symbols, if not I have to drop the call. That's the irule I've made but it's not working for some reason... when SIP_REQUEST { set meeting_nbr [findstr [SIP::header "INVITE"] ":" 1 "@"] if { not [string length $meeting_nbr] == 8} || { not [string length $meeting_nbr] == 0} { log local0. "SIP Drop [SIP::uri]" drop } } Please help. thanks.284Views0likes2CommentsSetting connection limit(call limit) to nodes while load balancing sip traffic over UDP
I have the following setup. SIP call is distributed from SBC to F5 LTM over UDP. Created a SIP persistence profile in LTM using call id as persistence key. Calls are being distributed to all nodes in the round robin and SIP messages are getting persisted. My requirement is to load balance the calls to the least active call node and limit the number of active calls to each node. i.e Nodes shall take only x number of active calls at any time. Active call is a call to which BYE is not received yet. Tried setting connection limit to each node but number of connections is always 1 on the statistics page. The connection limit is always 1 as in my case SIP is over UDP, source and destination IP & Port will be same for all calls. Is there any way in F5 LTM where we can limit the number of calls to each node and load balance the calls to the least call-taking node for SIP over UDP?596Views0likes0CommentsSIP TCP 5061 packets dropped by IP Forwarding Virtual Server
Hello I have a HA F5 LTM Solution running v14.1.2.3 I have an internal vlan (192.168.10.8 as Floating IP) and external vlan (192.168.13.5 as Floating IP) I also have an IP Forwarding Virtual Server that allows all 192.168.10.x servers to send packets through the F5 without making any NAT configuration. So servers in 192.168.10.0/24 network can send all protocol packets through the f5 to reach external networks. For example, 192.168.10.50 server sends a packet to 10.16.75.50 server. First, it reaches 192.168.10.8 (F5 internal vlan), then the packet is sent to a firewall (192.168.13.2 which is in the same vlan as external vlan in f5), then the firewall reaches 10.16.75.50 by static route or because it is one of its local networks. The problem comes when this packets are from SIP protocol (TCP 5061 SIP REGISTER), I see that the f5 drops this packets even though the IP Forwarding Virtual Server should allow them because it allows TCP packets and all ports are permitted. Do I need to create something different from my IP Forwarding virtual server? ps: When I run tcpdump in F5, I see SIP traffic coming to internal vlan interface but nothing egresses by the external vlan interface511Views0likes1CommentF5 LTM and simple centos voice server
i want to load balance 2 centos web servers created pool , pol members with port 5060 created udp profile choose udp for virtual server selected snat automap / in another time created a snat pool connected ip phone to the ip of the virtual server the ip phone registered succesfully but when the first back end server is down or forced down / the phone doesnt register to the second identical one it is stuck on the first526Views0likes4CommentsSIP MRF ALG Support for RFC-7315 Implicit Registration
Problem this snippet solves: The SIP MRF ALG, when used with an LSN pool, provides the ability to inspect SIP messages and modify all of the appropriate headers with a CGNAT LSN pool. However, in 3GPP IMS networks, the REGISTER message uses a different SIP ID than the ID that is used in subsequent messages, such as a SUBSCRIBE. If you try to deploy the F5 ALG in this scenario, the F5 will block the SUBSCRIBE message because the From header does not match what was stored in the registration database. This is called implicit registration, and it is the mechanism by which a user is allowed to register simultaneously more than one of his/her Public User Identities. When the initial REGISTER is sent by the UE, the F5 MRF ALG creates a database entry for the REGISTER event, and reserves and IP and port for the CGNAT translation. It keeps this listener and database entry alive until the end of the timeout in the EXPIRES header. The next message is the 200 OK for the REGISTER. This contains a P-Associated-URI that gets used by the client in subsequent requests. In subsequent messages, the client will use the value from the P-Associated-URI. When the F5 sees the To: and From: headers with the new value, it drops the message because it doesn’t match what is in the database for that connection and creates an error in the log that it is an unregistered subscriber. The iRule, to fix this problem, will watch for the SIP_RESPONSE event, which is triggered when the system receives a response from the server and the SIP headers have been parsed. This is before the “MR_INGRESS” event, which happens when the system is sending it to the Message Routing SIP MRF ALG. In the SIP_RESPONSE event, we look for a CSeq that matches “* REGISTER”. If we see this, we get the P-Associated-URI value, and create a table entry that is indexed by the P-Associated-URI value with a value equal to the ID that was in the REGISTER To and From headers. The table will have a timeout value equal to the Expires header that was in the 200 OK response for the REGISTER. When the SUBSCRIBE is sent and then this packet is received by the F5 and the SIP headers have been processed, it is known as the “SIP_REQUEST” event. When it is passed over to the MRF ALG, this is known as the “MR_INGRESS” event. In the SIP_REQUEST event, we look for a SUBSCRIBE message. We lookup the P-Associated-URI value in the From header, and see if there is a corresponding table entry. If there is, we save a copy of the SIP From, and To headers. We then replace those headers by changing the P-Associated-URI value back to the MCPTT value. Now, when MR_INGRESS fires, and it is sent to the SIP ALG, it sees that the From and To headers are the same as the database entry and it allow it. The next event, MR_EGRESS, means it has left the Message Routing ALG, and then the event that occurs is SIP_REQUEST_SEND. This means it has been processed by MRF, and is now being sent to the server. In the SIP_REQUEST_SEND event, we change the headers back to how they were originally. In addition, this iRule inserts and "ep=" header into the Contact header that contains the original client IP for a REGISTER message, and inserts a header called "P-UE-Flow-Info" that contains information about the original subscriber. This is needed by some CSCF servers. How to use this snippet: Create a virtual server with an MRF session and MRF routing profile and apply it. An example: ltm virtual vs-sip-alg-v6 { destination 2002:abcd:f5:20::.sip ip-protocol udp last-modified-time 2018-09-04:11:20:51 mask ffff:ffff:ffff:ffff:: profiles { my-siprouter-alg { } my-sipsession-alg { } udp { } } rules { SIP-Headers } source-address-translation { pool sip-alg-lsn-pool-v6 type lsn } translate-address enabled translate-port enabled vlans { clients } vlans-enabled vs-index 3 } ltm message-routing sip profile router my-siprouter-alg { app-service none defaults-from siprouter-alg traffic-group traffic-group-1 } ltm message-routing sip profile router siprouter-alg { app-service none defaults-from siprouter nonregister-subscriber-callout disabled operation-mode application-level-gateway traffic-group traffic-group-1 } ltm message-routing sip profile session my-sipsession-alg { app-service none defaults-from sipsession-alg } Code : when CLIENT_ACCEPTED { #Get info about client in variables to use later in other events like SIP_REQUEST_SEND #This is needed for inserting the P-UE-Flow-Info information set clientaddr [IP::client_addr] set clientport [UDP::client_port] set vip [IP::local_addr] set vipport [UDP::local_port] } when MR_INGRESS { } when MR_EGRESS { } when SIP_REQUEST { #Look at the SIP method. If it is a SUBSCRIBE, NOTIFY, or INVITE, we need to look this up in the table and switch "[SIP::method]" { "SUBSCRIBE" - "NOTIFY" - "INVITE" { #Mvalue is the value of the SIP ID inside the SIP::from header between the : and @ symbol #Example From: <>;tag=dc11036c the mvalue is +11395600061 set mvalue "[lindex [split [lindex [split [SIP::from] @] 0] :] 1]" #Lookup the value in the table that shows the original SIP ID in the REGISTER message #Example if it was From: <312670100004861>;tag=08bcb27c #Would be 312670100004861 #nvalue is that value we find in the table set nvalue "[table lookup $mvalue]" #Check if there is a table value. If so then grab old headers and then replace with new information if { $nvalue ne "" } { #Save the header values as X-From and X-To so we can put them back in the SIP_REQUEST_SEND event SIP::header insert X-From "[SIP::header value From]" SIP::header insert X-To "[SIP::header value To]" #Use these to pass into the procedure to get the new header value set oldfrom "[SIP::header value From]" set oldto "[SIP::header value To]" #Run proc to get the new header value that inserts new number into field set newfrom "[call replace_number_fromto_field $oldfrom $nvalue]" set newto "[call replace_number_fromto_field $oldto $nvalue]" #Replace the SIP From and To headers with the new values SIP::header replace From "$newfrom" SIP::header replace To "$newto" } } default { } } } when SIP_REQUEST_SEND { #If this is one of the events that we modified the headers, put the headers back the way they were. switch "[SIP::method]" { "SUBSCRIBE" - "NOTIFY" - "INVITE" { #Check if the X-From and X-To have anything in them. If they do, put the headers back with that information #Remove the X-From and X-To headers before sending to the server if { [SIP::header value X-From] ne "" } { SIP::header replace From "[SIP::header value X-From]" SIP::header remove X-From } if { [SIP::header value X-To] ne "" } { SIP::header replace To "[SIP::header value X-To]" SIP::header remove X-To } #The following only applies if this is an INVITE if { [SIP::method] eq "INVITE" } { #The following is the logic for inserting the P-UE-Flow-Info header #The UE address is just the client_address #The clientport is the UE original port set UE "\"\[$clientaddr\]:$clientport\"" #Find the audio port log local0. "First m= is [findstr [SIP::message] "m=audio " 8 " "] " set audioport "[findstr [SIP::message] "m=audio " 8 " "]" log local0. "Audioport is $audioport" set applicationport "[findstr [SIP::message] "m=application " 14 " "]" log local0. "Applicationport is $applicationport" set header "sig;src=$UE;msrc=\"\[[IP::local_addr]\]:$vipport\";dst=\"\[$vip\]:[UDP::local_port]\",audio;src=$UE;msrc=\"\[[IP::local_addr]\]:$vipport\";dst=\"\[$vip\]:[UDP::local_port]\"" log local0. "P-UE-Flow-Info header is = $header" SIP::header insert P-UE-Flow-Info "$header" } } default { } } } when SIP_RESPONSE { #log local0. "Message in response is [SIP::message]" #Check if response is a REGISTER. If so create a table entry for it #Table entry is indexed by the P-Associated-URI with a value of the original SIP ID in the REGISTER message switch -glob "[SIP::header value CSeq]" { "* REGISTER" { if { [SIP::header value P-Associated-URI] ne ""} { set myuri "[SIP::header value P-Associated-URI]" #Get the value between the : and the @ symbol #Example P-Associated-URI is #P-Associated-URI: <>,<> set pvalue "[lindex [split [lindex [split $myuri @] 0] :] 1]" #fvalue is the value between the : and @ symbol in the original from #example original from is sip:312670100004861@ims.mnc180.mcc310.3gppnetwork.org so fvalue is 312670100004861 set fvalue "[lindex [split [lindex [split [SIP::from] @] 0] :] 1]" #We need to look at the Contact header to determine the value of the Expires there #A procedure called find_expires returns 0 if it couldn't parse it and the number if it could # set expires "[call find_expires [SIP::header value Contact]]" #Create a table entry indexed by the P-Associated-URI as the key with a value equal to the original SIP ID table set $pvalue $fvalue $expires } else { #If there was no P-Associated-URI we can't create a table entry log local0. "No P-Associated-URI found for [SIP::from] [SIP::to] in REGISTER response" } } "default" { #Default action for an event that didn't match above } } } when SIP_RESPONSE_SEND { } proc find_expires { contact } { #Look for the word "expires=" and then get the number value after that and before the ";" character set found [scan [string range $contact [string first expires= $contact] end] {expires=%[0-9];} expires] #Return a value of 0 if the above couldn't be parsed properly #A good example is Contact: <312670100004861>;expires=3600;+sip.instance=" ";mobility="mobile";+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.mcptt";video;+g.3gpp.mcptt if { $found } { return $expires } else { return 0 } } proc replace_number_fromto_field { str newnumber } { #Parses the string passed in and splits it up into a scheme, number, domain, and tag #Then puts the newnumber string into there replacing the previous number #Supposed to be used with the SIP::header value from and SIP::header value to # scan $str {%[^:]:%[^@]@%[^;];%s} scheme number domain tag if { [info exists tag] } { set newheader "$scheme:$newnumber@$domain;$tag" } else { set newheader "$scheme:$newnumber@$domain" } return $newheader } proc replace_number_contact_field { str newnumber } { #Pass in a string called str and newnumber and replace the number in the string #Assumes a string similar to the following #Contact: <312670100004861>;+sip.instance=" ";mobility="mobile";+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.mcptt";video;+g.3gpp.mcptt #Split this up by first ":" the "@" symbol and remainder scan $str {%[^:]:%[^@]@%s} scheme number remainder set newheader "$scheme:$newnumber@$remainder" #Returns a header in the format above with the newnumber in place return $newheader }563Views0likes1CommentSIP 200 OK dropped when used NAT rules in LTM.
In one of our customer deployment, where BIG-IP LTM is used, sometime we have noticed that for certain SIP MESSAGE packets when 200 OK is received from SIP server, then LTM is dropping the 200 OK when NAT is configured. All the flow is happening over UDP. Can you please indicate any troubleshoot guide by which we can identify the possible reason of packet drop. does LTM has capability to identify SIP 200 OK of SIP MESSAGE only and due to some miss configuration it will get dropped. Please help278Views0likes1Comment