* RTP proxy module @ 2006-10-08 23:13 Tomas Mandys 2006-10-09 3:47 ` Glen Turner 2006-10-10 4:59 ` Patrick McHardy 0 siblings, 2 replies; 8+ messages in thread From: Tomas Mandys @ 2006-10-08 23:13 UTC (permalink / raw) To: netfilter-devel Hi, I'm engaged in SIP router development and now I need improve our current application concerning RTP proxy. SIP call need at least 2 UDP streams (RTP&RTCP) for each session. But problem is when one client is hidden behind the NAT. In this case a RPT proxy is essential. All RTP traffic goes through RTP proxy, in our case it was userspace application but because it need only redirect incomming packets to specified address or learn remote ip/port it's unnecessary copying rtp data between kernel and userspace. So I developed iptables module callled ipt_RTPPROXY+libipt_RTPPROXY that can do it in iptables, i.e. more efficiently. It's different case than connection tracking and NAT. It's not trivial, there is learning and expiration logic. I also developed userspace utils that can alloc, update, delete, list RTP sessions in iptables (using libipt_RTPPROXY). This is actually example how to encapsulate functionality in SIP router. The module is written as patch-o-matic-ng. Is it possible publish in netfilter.org CVS as (currently) experimental module? What procedure must new modules pass to be accepted? Note: I'm asking slightly in advance, not finished yet, I'm going to test. Next to do is HA support. Tomas ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RTP proxy module 2006-10-08 23:13 RTP proxy module Tomas Mandys @ 2006-10-09 3:47 ` Glen Turner 2006-10-10 4:59 ` Patrick McHardy 1 sibling, 0 replies; 8+ messages in thread From: Glen Turner @ 2006-10-09 3:47 UTC (permalink / raw) To: netfilter-devel Tomas Mandys wrote: > What procedure must new modules pass to be accepted? Some guidance on this would be appreciated. I've seen no response to my posting of a module on 5 October <http://lists.netfilter.org/pipermail/netfilter-devel/2006-October/025697.html> and I'm not sure if that is a good or a bad thing. Thanks, Glen ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RTP proxy module 2006-10-08 23:13 RTP proxy module Tomas Mandys 2006-10-09 3:47 ` Glen Turner @ 2006-10-10 4:59 ` Patrick McHardy 2006-10-10 7:51 ` Tomas Mandys 1 sibling, 1 reply; 8+ messages in thread From: Patrick McHardy @ 2006-10-10 4:59 UTC (permalink / raw) To: Tomas Mandys; +Cc: netfilter-devel Tomas Mandys wrote: > I'm engaged in SIP router development and now I need improve our current > application concerning RTP proxy. SIP call need at least 2 UDP streams > (RTP&RTCP) for each session. But problem is when one client is hidden behind > the NAT. In this case a RPT proxy is essential. All RTP traffic goes through > RTP proxy, in our case it was userspace application but because it need only > redirect incomming packets to specified address or learn remote ip/port it's > unnecessary copying rtp data between kernel and userspace. So I developed > iptables module callled ipt_RTPPROXY+libipt_RTPPROXY that can do it in > iptables, i.e. more efficiently. It's different case than connection tracking > and NAT. It's not trivial, there is learning and expiration logic. > > I also developed userspace utils that can alloc, update, delete, list RTP > sessions in iptables (using libipt_RTPPROXY). This is actually example how to > encapsulate functionality in SIP router. How is this different from the SIP conntrack/NAT helper, which can deal (well, not entirely yet) with clients behind NAT as well? > The module is written as patch-o-matic-ng. > Is it possible publish in netfilter.org CVS as (currently) experimental > module? What procedure must new modules pass to be accepted? We currently only accept patches for patch-o-matic that we have an interest in maintaining ourselves (in case the author disappears, which happens regulary). The two other possibilities are external patch-o-matic repositories and/or an account on people.netfilter.org if you just need some webspace to publish it. ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: RTP proxy module 2006-10-10 4:59 ` Patrick McHardy @ 2006-10-10 7:51 ` Tomas Mandys 2006-10-11 10:07 ` Patrick McHardy 0 siblings, 1 reply; 8+ messages in thread From: Tomas Mandys @ 2006-10-10 7:51 UTC (permalink / raw) To: netfilter-devel; +Cc: 'Patrick McHardy' > How is this different from the SIP conntrack/NAT helper, > which can deal > (well, not entirely yet) with clients behind NAT as well? There is dedicated port range for RTP proxy, let's say 2000 ports, so 500 simultaneous calls may "processed" at one moment. One port for RTP, second RTCP and both for each clients. Note data comming from opposite direction are engaged in different conntrack (6666->3000, 9000->3002) and 2 related streams are related each other (RTP, RTCP) Implementation via mangler, iptRTPPROXY changes in IP_PRE_ROUTING callback destination (e.g.9000) address to route correctly, IP_POST_CALLBACK rewrites source address (e.g.3002). There are more features, like timeouts, statistics etc. RTP session allocation is driven by SIP router via libipt_RTPPROXY. Because RTP stream are specified apart from SIP RTP proxy does not know anything about Call-id,fromtag,totag but only session-id. SIP router is responsible from connecting them. SIP is mentioned here as example (I need it for SIP). Here is simplified scenario (no STUN) +-------------+ +---------------+ +------------+ SIP(UDP/TCP) +-------------+ | SIP phone | | NAT box | --->| SIP router |<---------- | SIP phone | | UE#1 | | translates: | / | 2.3.4.5 | \ | UE#2 | | 192.168.1.1 |<---->| >1.2.3.4:6050 |<----- +------------+ ----->| 8.9.10.11 | | signalling | | | ^ | signalling | | port:5060 | | | |via libipt | port:5060 | | | | | v | | | | | | +------------------+ | | | | | | | lib_RTPPROXY | | | | | | | | RTP proxy in ipt | | | | | | | | 2.3.4.5 | | | | streaming | | | UDP | | | streaming | | RTP: 6000 |<---->| >1.2.3.4:6666 |<--------->| 3000<-- | | | | RTCP:6001 |<---->| >1.2.3.4:8888 |<--------->| 3001<- \ | UDP | | | | | | | \ ->3002 |<---------->| RTP: 9000 | | | | | | -->3003 |<---------->| RTCP:9001 | +-------------+ +---------------+ | 3004 | +-------------+ | 3005 | | 3006 | | 3007 | | 3008 | | | | .... | | | | .... | | | | 4000 | | | | | +------------------+ 1) UE#1 initiates call INVITE sip:ue2 Via: 192.168.1.1 Call-id: zxcvb From: <sip:ue1>;tag=123456 To: <sip:ue2> Contact: <sip:192.168.1.1:5060> Content-type: application/sdp c=IN IP4 192.168.1.1 m=audio 6000 RTP/AVP 0 a=rtpmap:0 PCMU/8000 2) sip router recognezes that UE behind NAT because Via!=dest address (1.2.3.4:6050). SIP need rewrite SIP message (it can do SIP signalling NAT stuff by itself) and need also rewrite SDP (note here when only one UE behind NAT it's RTP proxy not absolutely necessary). 2a) sip router demands one RTP session allocation at RTP proxy. RTP proxy allocates one quad and returns port number. 2b) SIP router rewrites SIP message (Contact and SDP) and sends to UE2 INVITE sip:ue2 Via: 2.3.4.5;received=1.2.3.5;rport=6050 UDP Via: 192.168.1.1 UDP Call-id: zxcvb From: <sip:ue1>;tag=123456 To: <sip:ue2> Contact: <sip:8.9.10.11> Content-type: application/sdp c=IN IP4 2.3.4.5 m=audio 3002 RTP/AVP 0 a=rtpmap:0 PCMU/8000 3) UE2 pick up phone SIP 200 OK Via: 2.3.4.5;received=1.2.3.5;rport=6050 UDP Via: 192.168.1.1 UDP Call-id: zxcvb From: <sip:ue1>;tag=123456 To: <sip:ue2>;tag=456788 Contact: <sip:1.2.3.4:6050> Content-type: application/sdp c=IN IP4 8.9.10.11 m=audio 9000 RTP/AVP 0 a=rtpmap:0 PCMU/8000 4) sip router rewrites reply (SDP) and tell RTP proxy remote address of UE#2 (RTP proxy may now traverse UDP streams) - note that autolerning of remote ip/port is supported, e.g. to learn 2.3.4.5:6666/8888 SIP 200 OK Via: 192.168.1.1 UDP Call-id: zxcvb From: <sip:ue1>;tag=123456 To: <sip:ue2>;tag=456788 Contact: <sip:192.168.1.1:5060> Content-type: application/sdp c=IN IP4 2.3.4.5 m=audio 3000 RTP/AVP 0 a=rtpmap:0 PCMU/8000 5) finally, UE#1 can send RTP data do 2.3.4.5:3000/3001 and UE2 to 2.3.4.5:3002/3003 6) when BYE arrives then RTP session is deallocated > We currently only accept patches for patch-o-matic that we have an > interest in maintaining ourselves (in case the author disappears, > which happens regulary). The two other possibilities are external > patch-o-matic repositories and/or an account on people.netfilter.org > if you just need some webspace to publish it. Maybe a link from netfilter.org to a separate sourceforge/berlios is OK when you are not interested. Tomas ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RTP proxy module 2006-10-10 7:51 ` Tomas Mandys @ 2006-10-11 10:07 ` Patrick McHardy 2007-06-27 18:32 ` lib_RTPPROXY module Tomas Mandys 0 siblings, 1 reply; 8+ messages in thread From: Patrick McHardy @ 2006-10-11 10:07 UTC (permalink / raw) To: Tomas Mandys; +Cc: netfilter-devel Tomas Mandys wrote: >>How is this different from the SIP conntrack/NAT helper, >>which can deal >>(well, not entirely yet) with clients behind NAT as well? > > > There is dedicated port range for RTP proxy, let's say 2000 ports, so > 500 simultaneous calls may "processed" at one moment. One port for RTP, > second RTCP and both for each clients. Note data comming from opposite > direction are engaged in different conntrack (6666->3000, 9000->3002) > and 2 related streams are related each other (RTP, RTCP) > > Implementation via mangler, iptRTPPROXY changes in IP_PRE_ROUTING > callback destination (e.g.9000) address to route correctly, > IP_POST_CALLBACK rewrites source address (e.g.3002). There are more > features, like timeouts, statistics etc. RTP session allocation is > driven by SIP router via libipt_RTPPROXY. Because RTP stream are > specified apart from SIP RTP proxy does not know anything about > Call-id,fromtag,totag but only session-id. SIP router is responsible > from connecting them. SIP is mentioned here as example (I need it for > SIP). > > > Here is simplified scenario (no STUN) > > [..] I'm not sure if iptables is really the best place to implement it, but I'll wait for your code. Please send it to the list once you think its ready. >>We currently only accept patches for patch-o-matic that we have an >>interest in maintaining ourselves (in case the author disappears, >>which happens regulary). The two other possibilities are external >>patch-o-matic repositories and/or an account on people.netfilter.org >>if you just need some webspace to publish it. > > > Maybe a link from netfilter.org to a separate sourceforge/berlios is OK > when you are not interested. We can add a link to an external pom repository. ^ permalink raw reply [flat|nested] 8+ messages in thread
* lib_RTPPROXY module 2006-10-11 10:07 ` Patrick McHardy @ 2007-06-27 18:32 ` Tomas Mandys 2007-06-27 18:55 ` Jan Engelhardt 2007-06-27 18:57 ` Rémi Denis-Courmont 0 siblings, 2 replies; 8+ messages in thread From: Tomas Mandys @ 2007-06-27 18:32 UTC (permalink / raw) To: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 3998 bytes --] Hi, so I've finally "finished" work on RTPPROXY module, it seems it works now for kernel 2.6.17.8. Could änybody review code? What this module should support is described in quoted text bellow and in relatively extensive netfilter-rtpptoxy-howto.txt plus in manpages in tar. I'm not sure if devel list accepts attachments so here is also the link http://www.2p.cz/tmp/netfilter-rtpproxy.tgz. Does exist a reasonable CVS/SVN repository related to netfilter (pom) where it could be placed? I don't preffer to establish for such particular library extra sourceforge project. Quoted from older email: > It was developed primary for VoIP by SIP to our current > application concerning RTP proxy. SIP call need at least 2 UDP streams > (RTP&RTCP) for each session. But problem is when one client is hidden behind > the NAT. In this case a RPT proxy is essential. All RTP traffic goes through > RTP proxy, in our case it was userspace application but because it need only > redirect incomming packets to specified address or learn remote ip/port it's > unnecessary copying rtp data between kernel and userspace. So I developed > iptables module callled ipt_RTPPROXY+libipt_RTPPROXY that can do it in > iptables, i.e. more efficiently. It's different case than connection tracking > and NAT. It's not trivial, there is learning and expiration logic. > I also developed userspace utils that can alloc, update, delete, list RTP > sessions in iptables (using libipt_RTPPROXY). This is actually example how to > encapsulate functionality in SIP router. > The module is written as patch-o-matic-ng. > Is it possible publish in netfilter.org CVS as (currently) experimental > module? What procedure must new modules pass to be accepted? Thanks Tomáš Mandys 2p plus, s.r.o. http://www.2p.cz > -----Original Message----- > From: Patrick McHardy [mailto:kaber@trash.net] > Sent: Wednesday, October 11, 2006 12:07 PM > To: Tomas Mandys > Cc: netfilter-devel@lists.netfilter.org > Subject: Re: RTP proxy module > > > Tomas Mandys wrote: > >>How is this different from the SIP conntrack/NAT helper, > >>which can deal > >>(well, not entirely yet) with clients behind NAT as well? > > > > > > There is dedicated port range for RTP proxy, let's say 2000 > ports, so > > 500 simultaneous calls may "processed" at one moment. One > port for RTP, > > second RTCP and both for each clients. Note data comming > from opposite > > direction are engaged in different conntrack (6666->3000, > 9000->3002) > > and 2 related streams are related each other (RTP, RTCP) > > > > Implementation via mangler, iptRTPPROXY changes in IP_PRE_ROUTING > > callback destination (e.g.9000) address to route correctly, > > IP_POST_CALLBACK rewrites source address (e.g.3002). There are more > > features, like timeouts, statistics etc. RTP session allocation is > > driven by SIP router via libipt_RTPPROXY. Because RTP stream are > > specified apart from SIP RTP proxy does not know anything about > > Call-id,fromtag,totag but only session-id. SIP router is responsible > > from connecting them. SIP is mentioned here as example (I > need it for > > SIP). > > > > > > Here is simplified scenario (no STUN) > > > > [..] > > I'm not sure if iptables is really the best place to implement it, > but I'll wait for your code. Please send it to the list once you > think its ready. > > >>We currently only accept patches for patch-o-matic that we have an > >>interest in maintaining ourselves (in case the author disappears, > >>which happens regulary). The two other possibilities are external > >>patch-o-matic repositories and/or an account on people.netfilter.org > >>if you just need some webspace to publish it. > > > > > > Maybe a link from netfilter.org to a separate > sourceforge/berlios is OK > > when you are not interested. > > We can add a link to an external pom repository. > [-- Attachment #2: netfilter-RTPPROXY.tgz --] [-- Type: application/x-compressed, Size: 35421 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: lib_RTPPROXY module 2007-06-27 18:32 ` lib_RTPPROXY module Tomas Mandys @ 2007-06-27 18:55 ` Jan Engelhardt 2007-06-27 18:57 ` Rémi Denis-Courmont 1 sibling, 0 replies; 8+ messages in thread From: Jan Engelhardt @ 2007-06-27 18:55 UTC (permalink / raw) To: Tomas Mandys; +Cc: netfilter-devel [-- Attachment #1: Type: TEXT/PLAIN, Size: 16493 bytes --] On Jun 27 2007 20:32, Tomas Mandys wrote: >so I've finally "finished" work on RTPPROXY module, it seems it works >now for kernel 2.6.17.8. >Could änybody review code? What this module should support is described >in quoted text bellow and in relatively extensive >netfilter-rtpptoxy-howto.txt plus in manpages in tar. I'm not sure if >devel list accepts attachments so here is also the link >http://www.2p.cz/tmp/netfilter-rtpproxy.tgz. (1) CRLF line endings -> LF. (2) I'd suggest writing xtables now. Make it xt_RTPPROXY. >#include <linux/module.h> >#include <linux/vmalloc.h> >#include <linux/skbuff.h> >#include <linux/ip.h> >#include <linux/netfilter_ipv4/ip_tables.h> <linux/netfilter/x_tables.h> >#include <linux/netfilter_ipv4/ip_conntrack.h> >#include <linux/netfilter_ipv4/ipt_RTPPROXY.h> >#include <linux/netfilter_ipv4/ip_nat.h> These files are probably outdated (use nf_* instead) >/* override pr_debug to printk even no DEBUG, just for development purposes */ >#if 1 >#undef pr_debug >#define pr_debug(fmt,arg...) printk(KERN_DEBUG fmt,##arg) >#endif Do not override pr_debug. Override DEBUG instead. >#define OPPOSITE_GATE(i) (i^1) Please comment this, it was quite confusing until I read further into the code. >/* interrupt-context, softirq?? */ hardirq or softirq. It should not make a big difference. (Read: keep it short in either case) >static unsigned int do_target(struct sk_buff **pskb, > const struct net_device *in, > const struct net_device *out, > unsigned int hooknum, > const struct xt_target *target, > const void *targinfo, > void *userinfo) >{ > const struct ipt_rtpproxy_target_info *info = targinfo; > struct iphdr *piph; Stray spaces. > struct udphdr *pudph; > struct ip_conntrack *ct; > enum ip_conntrack_info ctinfo; > u_int16_t port, *old_port, new_port; > u_int32_t ip, *old_ip, new_ip; > int input_gate, sess_no, is_rtcp; > struct ipt_rtpproxy_session *sess; > > /* we take care only for UDP protocol */ > if ((*pskb)->nh.iph->protocol != IPPROTO_UDP) > return IPT_CONTINUE; Remove this UDP check. It can be solved better. (See at the end.) > pr_debug("ipt_RTPPROXY: do_target(skb=%p, in=%p, out=%p, hooknum=%u, targetinfo=%p, userinfo=%p)\n", *pskb, in, out, hooknum, targinfo, userinfo); > /* Now we take destination ip:port from tuple, we'll do it instead of (*pskb)->nh.iph because > * it's non manipulable part of tuple and it has correct value in both PRE_ROUTING/LOCAL_OUT > * and POST_ROUTING (where &(*pskb)->nh.iph->daddr is already rewritten and is useless > * for identification of RTP session). It cannot be a reply (stream in opposite direction) > * beacuse the replies have different tuple */ > IP_NF_ASSERT(hooknum==NF_IP_PRE_ROUTING || hooknum==NF_IP_LOCAL_OUT || hooknum==NF_IP_POST_ROUTING || hooknum==NF_IP_LOCAL_IN); > pr_debug("ipt_RTPPROXY: do_target: ip_conntrack_get()\n"); > ct = ip_conntrack_get(*pskb, &ctinfo); > /* Connection must be valid and non reply - replies go in via opposite gate as originals, but allow CONTINUE not to block common communication not related to RTP, e.g. DNS */ > if (ctinfo >= IP_CT_IS_REPLY) { > pr_debug("ipt_RTPPROXY: do_target: ctinfo >= IP_CT_IS_REPLY, IPF_CONTINUE\n"); > return IPT_CONTINUE; > } CodingStyle would sure be good. > > /* get location to rewrite IP:port of UDP header, actually we need only first 8 bytes */ > pudph = (struct udphdr *)((*pskb)->data + (*pskb)->nh.iph->ihl*4); Do not cast. skb->nh.iph is also gone in later kernels. Use piph = ip_hdr(skb) instead and go from there (piph->ihl) > if (hooknum == NF_IP_PRE_ROUTING) { > /* when all stuff is running on one box 2xRTP client+RTPPROXY (devel purposes only ?) > * then after POSTROUTING follows PREROUTING immediately and netfilter > * leaves (*pskb)->nfct untouched and RTPPROXY is mystified, source IP:port is address of opposite gate. > * conntrack should be invalidated and refreshed > */ > if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != (*pskb)->nh.iph->daddr || > ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port) != ntohs(pudph->dest)) { > pr_debug("ipt_RTPPROXY: do_target: non-corresponding conntrack and dest address, local RTP routing?\n"); > return NF_DROP; > #if 0 > pr_debug("ipt_RTPPROXY: do_target: refreshing conntrack\n"); > nf_conntrack_put((*pskb)->nfct); /* causes kernel crash */ Then don't do it :) > nf_ct_untrack(*pskb); > return IPT_CONTINUE; > (*pskb)->nfct = NULL; > it's nt possible to call ip_conntrack_in from module and I don't other way how to refresh conntrack This does not look logical at all. (Oh never mind, it's #if 0ed. Remove?) > if (ip_conntrack_in(hooknum, pskb, in, out, NULL) == NF_DROP) { > return NF_DROP; > } > ct = ip_conntrack_get(*pskb, &ctinfo); > pr_debug("ipt_RTPPROXY: do_target: ctinfo >= IP_CT_IS_REPLY, IPF_CONTINUE\n"); > if (ctinfo >= IP_CT_IS_REPLY) { > return IPT_CONTINUE; > } > /* get location to rewrite IP:port of UDP header, actually we need only first 8 bytes */ > pudph = (struct udphdr *)((*pskb)->data + (*pskb)->nh.iph->ihl*4); > #endif > } > } > > IP_NF_ASSERT(ct && (ctinfo < IP_CT_IS_REPLY)); > ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; > port = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port); > > pr_debug("ipt_RTPPROXY: do_target:{ct->src: %d.%d.%d.%d:%u, ct->dst: %d.%d.%d.%d:%u} reply:{ct->src: %d.%d.%d.%d:%u, ct->dst: %d.%d.%d.%d:%u}, ctinfo: %u\n", > NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port), > NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port), > NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port), > NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port), > ctinfo); > > pr_debug("ipt_RTPPROXY: do_target:skb->iph.src: %d.%d.%d.%d:%u, skb->iph.dst: %d.%d.%d.%d:%u\n", > NIPQUAD((*pskb)->nh.iph->saddr), ntohs(pudph->source), > NIPQUAD((*pskb)->nh.iph->daddr), ntohs(pudph->dest) > ); > spin_lock_bh(&ipt_lock); > /* ip:port must be a port related to gate_a/b */ > for (input_gate=0, sess=NULL; input_gate < IPT_RTPPROXY_MAX_GATE; input_gate++) { > if (ip == info->gate[input_gate].ip) { > if (port >= info->gate[input_gate].port && port < info->gate[input_gate].port+2*info->max_sess) { > sess_no = (port-info->gate[input_gate].port) >> 1; > is_rtcp = (port-info->gate[input_gate].port) & 0x01; // TODO: check if may be also even port number > sess = info->switchboard->sessions + sess_no; > break; > } > } > } > if (!sess) { > spin_unlock_bh(&ipt_lock); > pr_debug("ipt_RTPPROXY: do_target: session not found, IPT_CONTINUE\n"); > return IPT_CONTINUE; > } > > pr_debug("ipt_RTPPROXY: do_target: session found\n"); > if (!(*pskb)->tstamp.off_sec) > __net_timestamp(*pskb); > > switch (hooknum) { > case NF_IP_PRE_ROUTING: > case NF_IP_LOCAL_OUT: > /* check if session is active */ > switch (sess->state) { > case ipt_rtpproxy_INIT1: > case ipt_rtpproxy_INIT2: > case ipt_rtpproxy_FORWARD1: > case ipt_rtpproxy_FORWARD2: > break; > default: > spin_unlock_bh(&ipt_lock); > pr_debug("ipt_RTPPROXY: do_target: sess->state=%d, NF_DROP\n", sess->state); > return NF_DROP; > } > > /* check if session is still active */ > if (sess->expires < (*pskb)->tstamp.off_sec) { > info->switchboard->so.stat.state[sess->state]--; > sess->state = ipt_rtpproxy_EXPIRED; > info->switchboard->so.stat.state[sess->state]++; > spin_unlock_bh(&ipt_lock); > pr_debug("ipt_RTPPROXY: do_target: session expired, NF_DROP\n"); > return NF_DROP; > } > > if (sess->gate[input_gate].stream[is_rtcp].source.ip != (*pskb)->nh.iph->saddr || sess->gate[input_gate].stream[is_rtcp].source.port != ntohs(pudph->source)) { > if (sess->gate[input_gate].stream[is_rtcp].learning >= (*pskb)->tstamp.off_sec) { > /* learn source address:port */ > sess->gate[input_gate].stream[is_rtcp].source.ip = (*pskb)->nh.iph->saddr; > sess->gate[input_gate].stream[is_rtcp].source.port = ntohs(pudph->source); > if (!sess->gate[input_gate].always_learn) > sess->gate[input_gate].stream[is_rtcp].learning = 0; /* learn only once */ > /* sess->gate[input_gate].learnt = (*pskb)->tstamp; */ > } > else { > /* drop unlearnable packet silently */ > spin_unlock_bh(&ipt_lock); > pr_debug("ipt_RTPPROXY: do_target: unlearnable packet, NF_DROP\n"); > return NF_DROP; > } > } > /* rewrite destination address to opposite side (learnt/forced IP:port) */ > if (sess->gate[OPPOSITE_GATE(input_gate)].stream[is_rtcp].source.ip == 0) { > /* not learnt/received any packet from opposite side, we cannot forward it */ > if (sess->gate[OPPOSITE_GATE(input_gate)].stream[is_rtcp].learning >= (*pskb)->tstamp.off_sec) { > /* if we don't missed chance forever to learn opposite address then prolong expires even we cannot forward the packet */ > sess->expires = (*pskb)->tstamp.off_sec+info->expires_timeout; > } > spin_unlock_bh(&ipt_lock); > pr_debug("ipt_RTPPROXY: do_target: no packet received from opposite side, NF_DROP\n"); > return NF_DROP; > } > switch (sess->state) { > case ipt_rtpproxy_INIT2: > info->switchboard->so.stat.state[sess->state]--; > sess->state = ipt_rtpproxy_FORWARD1; /* first forwarded packet */ > info->switchboard->so.stat.state[sess->state]++; > break; > case ipt_rtpproxy_FORWARD1: > if (sess->gate[OPPOSITE_GATE(input_gate)].stream[is_rtcp].last_packet_stamp) { > /* we've already got packet from opposite side (of the same stream!) */ > info->switchboard->so.stat.state[sess->state]--; > sess->state = ipt_rtpproxy_FORWARD2; > info->switchboard->so.stat.state[sess->state]++; > } > break; > } > > new_ip = sess->gate[OPPOSITE_GATE(input_gate)].stream[is_rtcp].source.ip; > new_port = sess->gate[OPPOSITE_GATE(input_gate)].stream[is_rtcp].source.port; > > sess->gate[input_gate].stat.packets_in++; > sess->gate[input_gate].stat.bytes_in += pudph->len; > info->switchboard->so.gate[input_gate].stat.packets_in++; > info->switchboard->so.gate[input_gate].stat.bytes_in += pudph->len; > sess->expires = (*pskb)->tstamp.off_sec+info->expires_timeout; > sess->gate[input_gate].stream[is_rtcp].last_packet_stamp = (*pskb)->tstamp.off_sec; > break; > > case NF_IP_POST_ROUTING: > case NF_IP_LOCAL_IN: > /* rewrite source address to proxy gate */ > new_ip = info->gate[OPPOSITE_GATE(input_gate)].ip; > new_port = info->gate[OPPOSITE_GATE(input_gate)].port+2*sess_no+is_rtcp; > > sess->gate[OPPOSITE_GATE(input_gate)].stat.packets_out++; > sess->gate[OPPOSITE_GATE(input_gate)].stat.bytes_out += pudph->len; > info->switchboard->so.gate[OPPOSITE_GATE(input_gate)].stat.packets_out++; > info->switchboard->so.gate[OPPOSITE_GATE(input_gate)].stat.bytes_out += pudph->len; > break; > > default: /* never happens */ > spin_unlock_bh(&ipt_lock); > pr_debug("ipt_RTPPROXY: do_target: unexpected hooknum = %d, IPT_CONTINUE\n", hooknum); > return IPT_CONTINUE; > } > spin_unlock_bh(&ipt_lock); > > if (!skb_make_writable(pskb, sizeof(*piph))) { /* it changes *pskb !!! */ > pr_debug("ipt_RTPPROXY: do_target: !skb_make_writable\n"); > return NF_DROP; > } > > pudph = (struct udphdr *)((*pskb)->data + (*pskb)->nh.iph->ihl*4); No cast. > switch (hooknum) { > case NF_IP_PRE_ROUTING: > case NF_IP_LOCAL_OUT: > old_ip = &(*pskb)->nh.iph->daddr; > old_port = &pudph->dest; > /* dst_release((*pskb)->dst); idea taken from NAT but does not work > (*pskb)->dst = NULL; */ > break; > case NF_IP_POST_ROUTING: > case NF_IP_LOCAL_IN: > old_ip = &(*pskb)->nh.iph->saddr; > old_port = &pudph->source; > break; > default: > return NF_DROP; /* never happen */ > } > #if 0 > if (hooknum == NF_IP_LOCAL_OUT) { > /* bug: seems checksum is incorrect for locally generated udp packets, e.g. data not counted, seems also ^0xFFFFed (kernel 2.6.17.8) */ > pudph->check = 0; > } > #endif > if (pudph->check) { > /* rewrite UDP checksum if provided */ > pudph->check = > ip_nat_cheat_check(~(*old_ip), new_ip, > ip_nat_cheat_check((*old_port)^0xFFFF /* do not use '~', it's only u_int16 ! */, htons(new_port), pudph->check) > ); > } > > /* rewrite also IP header checksum */ > (*pskb)->nh.iph->check = ip_nat_cheat_check(~(*old_ip), new_ip, (*pskb)->nh.iph->check); > > pr_debug("ipt_RTPPROXY: do_target: old_addr: %d.%d.%d.%d:%u, new_addr: %d.%d.%d.%d:%u\n", NIPQUAD(*old_ip), ntohs(*old_port), NIPQUAD(new_ip), new_port); > *old_port = htons(new_port); > *old_ip = new_ip; > >// skb->nfcache |= NFC_ALTERED; > pr_debug("ipt_RTPPROXY: do_target: NF_ACCEPT\n"); > return NF_ACCEPT; >} > >/* recheck session status and calc statistics by state, ipt_lock+ipt_usercontext_mutex must be aquired */ >static inline void ipt_do_session_audit(struct timeval *stamp, struct ipt_rtpproxy_switchboard *switchboard, struct ipt_rtpproxy_session *sess) >{ > switch (sess->state) { > case ipt_rtpproxy_INIT1: > case ipt_rtpproxy_INIT2: > case ipt_rtpproxy_FORWARD1: > case ipt_rtpproxy_FORWARD2: > if (sess->expires < stamp->tv_sec) { > switchboard->so.stat.state[sess->state]--; > sess->state = ipt_rtpproxy_EXPIRED; > switchboard->so.stat.state[sess->state]++; > switchboard->so.stat.counter.expired++; > } > break; > default: > break; > } > switch (sess->state) { > case ipt_rtpproxy_EXPIRED: > case ipt_rtpproxy_DESTROYED: > if (sess->expires + switchboard->so.resurrection_timeout < stamp->tv_sec) { > switchboard->so.stat.state[sess->state]--; > sess->state = ipt_rtpproxy_NONE; > switchboard->so.stat.state[sess->state]++; > } > default: ; > } >} > >/* userspace related communication, ipt_usercontext_mutex must be aquired */ >static inline struct ipt_rtpproxy_switchboard* ipt_find_switchboard(struct ipt_rtpproxy_sockopt_in_switchboard *switchboard, int *opposite_flag) >{ > struct ipt_rtpproxy_switchboard *p; > int j, port_fl; > > /* this is helper, if ip-a==ip-b then port-a must not be equal to port.b but because client may not know port-b > we'll find it */ > port_fl = switchboard->gate[0].ip == switchboard->gate[OPPOSITE_GATE(0)].ip && > switchboard->gate[0].port == switchboard->gate[OPPOSITE_GATE(0)].port; > > for (p = switchboard_reg; p ; p = p->next ) { > for (j=0; j<IPT_RTPPROXY_MAX_GATE; j++) { > if ( p->so.gate[0].addr.ip == switchboard->gate[j].ip && > p->so.gate[0].addr.port == switchboard->gate[j].port && > p->so.gate[OPPOSITE_GATE(0)].addr.ip == switchboard->gate[OPPOSITE_GATE(j)].ip && > (p->so.gate[OPPOSITE_GATE(0)].addr.port == switchboard->gate[OPPOSITE_GATE(j)].port || port_fl) ) { > switchboard->gate[OPPOSITE_GATE(j)].port = p->so.gate[OPPOSITE_GATE(0)].addr.port; /* meaningful when port_fl */ > *opposite_flag = (j==0)?0:1; *opposite_flag = (j != 0); should be sufficient. > return p; > } > } > } > return NULL; >} > >/* there is no uniq cmd numbering space, 2 separates for GET and SET */ >#define IPT_OPT_SET_CMD 0x8000 > >static struct ipt_target ipt_rtpproxy_reg = { > .name = "RTPPROXY", > .target = do_target, > .targetsize = sizeof(struct ipt_rtpproxy_target_info), > .checkentry = do_checkentry, > .destroy = do_destroy, > .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) | (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN), > .table = "mangle", > .me = THIS_MODULE .proto = IPPROTO_UDP, >}; That will limit it to UDP. > /* Allocate one page as temporary storage */ > pr_debug("ipt_RTPPROXY: init(): __get_free_page(GFP_KERNEL)\n"); > if ((ipt_tmpbuf = (void*)__get_free_page(GFP_KERNEL)) == NULL) { > printk(KERN_ERR "ipt_RTPPROXY: Out of memory for temporary buffer page\n"); > goto error_cleanup; > } Why not use kmalloc instead? Jan -- ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: lib_RTPPROXY module 2007-06-27 18:32 ` lib_RTPPROXY module Tomas Mandys 2007-06-27 18:55 ` Jan Engelhardt @ 2007-06-27 18:57 ` Rémi Denis-Courmont 1 sibling, 0 replies; 8+ messages in thread From: Rémi Denis-Courmont @ 2007-06-27 18:57 UTC (permalink / raw) To: Tomas Mandys; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 918 bytes --] Le mercredi 27 juin 2007, Tomas Mandys a écrit : > Hi, > so I've finally "finished" work on RTPPROXY module, it seems it works > now for kernel 2.6.17.8. (...) > http://www.2p.cz/tmp/netfilter-rtpproxy.tgz. "RTP proxy is vulnerable for a while when is waiting for data to learn source address. We can decrease probability by reasonable learning timeout." I disagree here. Do the math, or run the attack tests yourself, it takes quite little bandwidth to denial (and hijack calls from) a "promiscuous" RTP proxy, even with randomized ports numbers within a large port range. 12 or even 14 bits of entropy are seldom acceptable. Like it or not, the only "safe" ways to run SIP behind NATs requires either, encryption (e.g. SRTP), some NAT traversal mechanism on the clients (e.g. ICE) or an ALG within the client's own NAT. Regards, -- Rémi Denis-Courmont http://www.remlab.net/ [-- Attachment #2: This is a digitally signed message part. --] [-- Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-06-27 18:57 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-10-08 23:13 RTP proxy module Tomas Mandys 2006-10-09 3:47 ` Glen Turner 2006-10-10 4:59 ` Patrick McHardy 2006-10-10 7:51 ` Tomas Mandys 2006-10-11 10:07 ` Patrick McHardy 2007-06-27 18:32 ` lib_RTPPROXY module Tomas Mandys 2007-06-27 18:55 ` Jan Engelhardt 2007-06-27 18:57 ` Rémi Denis-Courmont
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.