/* * IP_MASQ_H323, H.323 masquerading module * * * Version: 2.2.1 - 20 April 2001 * * Author: Rajkumar. S * Archana V. S. * Sheenarani I. * * ____Released by CoRiTeL (www.coritel.it)___ * Luca Veltri * Stefano Giacometti * Raffaele Pellicciotta * Paolo Iurilli * * to work on kernel 2.2.12 and NetMeeting 3.01 * * official site: http://www.coritel.it/projects/sofia/nat.html * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Fixes: * Juan Jose Ciarlante: coding cleanups * Paolo Iurilli,Luca Veltri: * CORITEL 04.09.00: ip_masq_h225_app and ip_masq_h245_app dynamic allocation cleanups * Paolo Iurilli: * CORITEL: incoming calls code integration and ip_masq_timeout_table introduction * */ #include #include #include #include #include #include #include #include #include #include #define IP_MASQ_H323_DEBUG(msg...) (1-debug<=ip_masq_get_debug_level())? printk(KERN_DEBUG "IP_MASQ:" ## msg) : 0 static int debug=0; MODULE_PARM(debug, "i"); /* * port_h225 is set to the default h.225 port (1720) */ int port_h225 = 1720; /* CORITEL 29/09/2000 : private h323 timeout table */ struct ip_masq_timeout_table h323_timeout_table = { ATOMIC_INIT(0), /* refcnt */ 0, /* scale */ { 30*60*HZ, /* IP_MASQ_S_NONE, */ 15*60*HZ, /* IP_MASQ_S_ESTABLISHED */ 10*60*HZ, /* IP_MASQ_S_SYN_SENT, */ 10*60*HZ, /* IP_MASQ_S_SYN_RECV, */ 1*60*HZ, /* IP_MASQ_S_FIN_WAIT, */ 10*60*HZ, /* IP_MASQ_S_TIME_WAIT, */ 5*60*HZ, /* IP_MASQ_S_CLOSE, */ 5*60*HZ, /* IP_MASQ_S_CLOSE_WAIT, */ 10*60*HZ, /* IP_MASQ_S_LAST_ACK, */ 2*60*HZ, /* IP_MASQ_S_LISTEN, */ 10*60*HZ, /* IP_MASQ_S_UDP, */ 10*60*HZ, /* IP_MASQ_S_ICMP, */ 2*HZ, /* IP_MASQ_S_LAST */ }, /* timeout */ }; /*@@@@@ private comments (CoRiTeL)... * some notes: * For every call from private host: * 1) every h.225 session regists a new 'h245 application' to handle * with a new h.245 session, this 'h245 appl.' is always registered with * the same ip_masq_h245 structure; for this reason only * one h245 session can be handled in the same time; * 2) for this reason, * when a new h245 session is needed, the old one is deregistrated and the * 'attach' value is decreased of one; * For every call from public host: * 1) a new ip_masq entry is made for H.245 tcp connection * 2) a new h245 application is binded to the ip_masq entry made without * registration */ /* Added by Alin Nastac 20.04.2001 */ int netmeeting_register_ip_masq_app(struct ip_masq_app* mapp, unsigned proto, __u16 port, int bSaveAttach) { int ret1, ret2; int n_attach_saved=mapp->n_attach; int n_attach_saved2=(mapp+1)->n_attach; mapp->type = IP_MASQ_APP_TYPE_PP(IP_MASQ_APP_INBOUND, proto, port); (mapp+1)->type = IP_MASQ_APP_TYPE_PP(IP_MASQ_APP_OUTBOUND, proto, port); ret1 = register_ip_masq_app_type(mapp); ret2 = register_ip_masq_app_type(mapp+1); if(bSaveAttach) { mapp->n_attach=n_attach_saved; (mapp+1)->n_attach=n_attach_saved2; } return ret1 ? ret1 : ret2; } int netmeeting_unregister_ip_masq_app(struct ip_masq_app* mapp, int bSaveAttach) { int ret1, ret2; int n_attach_saved=mapp->n_attach; int n_attach_saved2=(mapp+1)->n_attach; ret1 = unregister_ip_masq_app(mapp); ret2 = unregister_ip_masq_app(mapp+1); if(bSaveAttach) { mapp->n_attach=n_attach_saved; (mapp+1)->n_attach=n_attach_saved2; } return ret1 ? ret1 : ret2; } /* CORITEL 05.09.00: * Move an ip_masq_app from an old port to a new port */ int ip_masq_move_app(struct ip_masq_app* mapp, unsigned short protocol, int new_port) { int n_attach_saved=mapp->n_attach; int n_attach_saved2=(mapp+1)->n_attach; mapp->n_attach=0; (mapp+1)->n_attach=0; if(netmeeting_unregister_ip_masq_app(mapp, 0)) { /* deregistration failed */ mapp->n_attach=n_attach_saved; (mapp+1)->n_attach=n_attach_saved2; return -2; } else if (netmeeting_register_ip_masq_app(mapp, protocol, new_port, 0)) { /* registration failed */ mapp->n_attach=n_attach_saved; (mapp+1)->n_attach=n_attach_saved2; return -1; } else { mapp->n_attach=n_attach_saved; (mapp+1)->n_attach=n_attach_saved2; return 0; } } /* CORITEL 11.09.00 * unbind ip_masq */ int ip_masq_unbind_app(struct ip_masq *ms) { struct ip_masq_app * mapp; mapp = ms->app; if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP) return 0; if (mapp != NULL) { if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms); ms->app = NULL; mapp->n_attach--; } return (mapp != NULL); } /* CORITEL 08.09.00 * Bind ip_masq to a specific ip_masq_app, only for incoming calls */ struct ip_masq_app* ip_masq_bind_this_app(struct ip_masq* ms, struct ip_masq_app* mapp) { if (mapp == NULL) return NULL; /* allow binding if already bound */ if (ms->app != NULL) { IP_MASQ_H323_DEBUG("ip_masq_bind_this_app() called for already bound object: old app REPLACED!\n"); ip_masq_unbind_app(ms); } else IP_MASQ_H323_DEBUG("ip_masq_bind_this_app() called for not yet bound object!\n"); ms->app = mapp; if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms); mapp->n_attach++; return mapp; } int h245registered=0; struct ip_masq_app * masq_h245_app_debug; /********** Start of H.245 masq app functions ******************/ static int masq_h245_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) { /* setup the control connection with a new timeout table */ if (!ms->timeout_table){ ms->timeout_table = &h323_timeout_table; IP_MASQ_H323_DEBUG("masq_h245_init_1: ## NEW TIMEOUT TABLE ##\n"); } IP_MASQ_H323_DEBUG("masq_h245_init_1: IP masq app 245 init\n"); MOD_INC_USE_COUNT; return 0; } static int masq_h245_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) { MOD_DEC_USE_COUNT; IP_MASQ_H323_DEBUG("masq_h245_done_1: IP masq app 245 done\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); return 0; } int masq_h245_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) { IP_MASQ_H323_DEBUG("masq_h245_in\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); return 0; } int masq_h245_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) { struct sk_buff *skb; struct iphdr *iph; struct tcphdr *th; unsigned char *data, *data_limit; unsigned char *skbuff_p; __u16 data_port, *rtp_port; __u32 data_ip, *rtp_ip; struct ip_masq * n_ms_rtp; skb = *skb_p; iph = skb->h.ipiph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = skb->data; data_limit = skb->tail; skbuff_p = data+12; IP_MASQ_H323_DEBUG("masq_h245_out\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); /*@@@@@ CoRiTeL: analisys of h245 msg */ data=skb->data; /*@@@@@ CoRiTeL: start of IP pkt */ data+=iph->ihl*4+th->doff*4; /*@@@@@ CoRiTeL: jumps to app data */ while((data+5)saddr) { data_port=*((__u16*)(data+4)); IP_MASQ_H323_DEBUG("masq_h245_out: <-- RTCP/RTP_dest: %d.%d.%d.%d:%d\n",NIPQUAD(data_ip), data_port); n_ms_rtp = ip_masq_new( IPPROTO_UDP, maddr,0, /*@@@@@ CoRiTeL: masq addr */ data_ip, data_port, /*@@@@@ CoRiTeL: pck source */ iph->daddr, 0, /*@@@@@ CoRiTeL: pck dest */ IP_MASQ_F_NO_DPORT); if(n_ms_rtp==NULL) IP_MASQ_H323_DEBUG("masq_h245_out: RTCP/RTP masq entry not made\n"); else { ip_masq_control_add(n_ms_rtp,ms); ip_masq_listen(n_ms_rtp); ip_masq_put(n_ms_rtp); /* CORITEL 02/10/2000 */ /* setup the control connection with a new timeout table */ if (!n_ms_rtp->timeout_table){ n_ms_rtp->timeout_table = &h323_timeout_table; IP_MASQ_H323_DEBUG("masq_h245_out :## setup NEW TIMEOUT TABLE\n ##"); } rtp_ip=(__u32*)data; rtp_port=(__u16*)(data+4); /* Hack the packet */ *rtp_ip=n_ms_rtp->maddr; *rtp_port=n_ms_rtp->mport; IP_MASQ_H323_DEBUG("masq_h245_out: RTCP/RTP masquerated: maddr=%d.%d.%d.%d , mport=%u\n", NIPQUAD(n_ms_rtp->maddr),ntohs(n_ms_rtp->mport)); } } data++; } return 0; } /***********End of H.245 app functions *******************/ struct ip_masq_app ip_masq_h245_app [2] = { { NULL, /* next */ "h245_inbound", /* name */ 0, /* type */ 0, /* n_attach */ masq_h245_init_1, /* ip_masq_init_1 */ masq_h245_done_1, /* ip_masq_done_1 */ masq_h245_out, /* pkt_out */ masq_h245_in, /* pkt_in */ }, { NULL, /* next */ "h245_outbound", /* name */ 0, /* type */ 0, /* n_attach */ masq_h245_init_1, /* ip_masq_init_1 */ masq_h245_done_1, /* ip_masq_done_1 */ masq_h245_out, /* pkt_out */ masq_h245_in, /* pkt_in */ } }; static int masq_h225_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) { IP_MASQ_H323_DEBUG("masq_h225_init_1\n"); /* setup the control connection with a new timeout table */ if (!ms->timeout_table){ ms->timeout_table = &h323_timeout_table; IP_MASQ_H323_DEBUG("masq_h225_init_1: ## NEW TIMEOUT TABLE ##\n"); } MOD_INC_USE_COUNT; return 0; } static int masq_h225_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) { IP_MASQ_H323_DEBUG("masq_h225_done_1\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); IP_MASQ_H323_DEBUG("masq_h225: h245 status (0=unregistered, 1=registered) = %d\n",h245registered); /*@@@@@ CoRiTeL: debug*/ MOD_DEC_USE_COUNT; return 0; } int masq_h225_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) { /* CORITEL 08.09.00: */ struct sk_buff *skb; struct iphdr *iph; struct tcphdr *th; unsigned char *data, *data_limit; unsigned char *skbuff_p; __u16 data_port, *h245_port; __u32 data_ip, *h245_ip; struct ip_masq *n_ms; int f_alarm; /*CORITEL 06/10/2000: patch for voxilla, unnecessary for netmeeting and perhaps other application, voxilla makes some false alarm */ IP_MASQ_H323_DEBUG("masq_h225_out:\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); skb = *skb_p; iph = skb->h.ipiph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = skb->data; data_limit = skb->tail; skbuff_p = data+12; /* CORITEL: analisys of h225 msg */ data=skb->data; data+=iph->ihl*4+th->doff*4; f_alarm=0; while((data+5)saddr) { data_port=*((__u16*)(data+4)); /* CORITEL: incoming call from private host: substitution addr and port field in payload msg only */ if(data_port==ms->sport) { h245_ip=(__u32*)data; h245_port=(__u16*)(data+4); /* Hack the packet */ *h245_ip=ms->maddr; *h245_port=ms->mport; f_alarm=1;/* patch for voxilla */ IP_MASQ_H323_DEBUG("masq_h225_out: call from private host substitution addr and port field/n"); } else if(!f_alarm) /* CORITEL: incoming call from public host: new ip_masq entry */ { IP_MASQ_H323_DEBUG("masq_h225_out: private host:port <-- %d.%d.%d.%d:%d\n",NIPQUAD(data_ip), data_port); IP_MASQ_H323_DEBUG("masq_h225_out:It means that the call is incoming from public host!\n"); n_ms = ip_masq_new( IPPROTO_TCP, maddr,0, data_ip, data_port, iph->daddr, 0, IP_MASQ_F_NO_DPORT); if(n_ms==NULL) IP_MASQ_H323_DEBUG("masq_h225_out: h245 ip_masq entry not made\n"); else { ip_masq_control_add(n_ms,ms); ip_masq_listen(n_ms); ip_masq_put(n_ms); /* CORITEL 02/10/2000 */ /* setup the control connection with a new timeout table */ if (!n_ms->timeout_table){ n_ms->timeout_table = &h323_timeout_table; IP_MASQ_H323_DEBUG("masq_h225_out : ## NEW TIMEOUT TABLE ##\n"); } h245_ip=(__u32*)data; h245_port=(__u16*)(data+4); /* Hack the packet */ *h245_ip=n_ms->maddr; *h245_port=n_ms->mport; IP_MASQ_H323_DEBUG("masq_h225_out: masquerated: maddr=%d.%d.%d.%d , mport=%u\n", NIPQUAD(n_ms->maddr),ntohs(n_ms->mport)); ip_masq_bind_this_app(n_ms,ip_masq_h245_app); /* no registration of ip_masq_h245_app */ } } } data++; } return 0; } int masq_h225_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) { struct sk_buff *skb; struct iphdr *iph; struct tcphdr *th; unsigned char *data, *data_limit; __u32 source_ip,m_ip; __u16 port; __u32 temp_ip,*h225_ip; unsigned char *skbuff_p; unsigned char p1,p2; int result; IP_MASQ_H323_DEBUG("masq_h225_in\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); skb = *skb_p; iph = skb->h.ipiph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = skb->data; data_limit = skb->tail; skbuff_p = data+12; source_ip= (((*skbuff_p) << 24) + (*(skbuff_p+1)<< 16) + (*(skbuff_p+2) << 8) + (*(skbuff_p+3))); skbuff_p=skbuff_p+4; temp_ip= (((*skbuff_p) << 24) + (*(skbuff_p+1)<< 16) + (*(skbuff_p+2) << 8) + (*(skbuff_p+3))); while(((skbuff_p+6)< data_limit) && (temp_ip !=source_ip)){ skbuff_p++; temp_ip= (((*skbuff_p) << 24) + (*(skbuff_p+1)<< 16) + (*(skbuff_p+2) << 8) + (*(skbuff_p+3))); } if(temp_ip==source_ip){ p1=*(skbuff_p+4); p2=*(skbuff_p+5); port=(p1<<8)+p2; IP_MASQ_H323_DEBUG("masq_h225_in: H.245 Port is at: %u\n",port); /* CORITEL 05.09.00: bind the h245_app on the new port: - first, deregister the old ip_masq_h245_app, - then, register it on the new port. */ if (h245registered) { IP_MASQ_H323_DEBUG("masq_h225_in: found an old ip_masq_app entry for h245, I'm try to deregist it and regist the new port...\n"); result=ip_masq_move_app(ip_masq_h245_app,IPPROTO_TCP,port); switch (result) { case -2 : IP_MASQ_H323_DEBUG("masq_h225_in: deregistration failed\n"); break; case -1 : IP_MASQ_H323_DEBUG("masq_h225_in: deregistration OK, registration failed\n"); h245registered--; break; case 0 : IP_MASQ_H323_DEBUG("masq_h225_in: registration OK\n"); } } else { if (netmeeting_register_ip_masq_app(ip_masq_h245_app, IPPROTO_TCP, port, 1)==0) { /* registration OK */ h245registered=1; IP_MASQ_H323_DEBUG("masq_h225_in: registration of new h245_app OK\n"); } else IP_MASQ_H323_DEBUG("masq_h225_in: registration of new h.245 _app failed\n"); } } /* CORITEL 26/09/2000 */ /* CORITEL: incoming call from public host: substitution */ skbuff_p=data+16; m_ip=ntohl(ms->maddr); while(((skbuff_p+6)< data_limit) && (temp_ip!=m_ip)){ skbuff_p++; temp_ip= (((*skbuff_p) << 24) + (*(skbuff_p+1)<< 16) + (*(skbuff_p+2) << 8) + (*(skbuff_p+3))); } if (temp_ip==m_ip) { /* Hack the packet */ h225_ip=(__u32*)skbuff_p; *h225_ip=ms->saddr; } return 0; } struct ip_masq_app ip_masq_h225_app [2] = { { NULL, /* next */ "h225_inbound", /* name */ 0, /* type */ 0, /* n_attach */ masq_h225_init_1, /* ip_masq_init_1 */ masq_h225_done_1, /* ip_masq_done_1 */ masq_h225_out, /* pkt_out */ masq_h225_in, /* pkt_in */ }, { NULL, /* next */ "h225_outbound", /* name */ 0, /* type */ 0, /* n_attach */ masq_h225_init_1, /* ip_masq_init_1 */ masq_h225_done_1, /* ip_masq_done_1 */ masq_h225_out, /* pkt_out */ masq_h225_in, /* pkt_in */ } }; /* * ip_masq_h225 initialization */ int ip_masq_h225_init(void) { IP_MASQ_H323_DEBUG("ip_masq_h225_init\n"); if (netmeeting_register_ip_masq_app(ip_masq_h225_app, IPPROTO_TCP, port_h225, 0)) IP_MASQ_H323_DEBUG("ip_masq_h225_init: H323: ERROR loading h225 support on port = %d\n", port_h225); else IP_MASQ_H323_DEBUG("ip_masq_h225_init: H323: loaded h225 support on port = %d\n", port_h225); return 0; } /* * ip_masq_h225 fin. */ int ip_masq_h225_done(void) { IP_MASQ_H323_DEBUG("ip_masq_h225_done\n"); IP_MASQ_H323_DEBUG("masq_h245_app.n_attach= %d\n",masq_h245_app_debug->n_attach); if (netmeeting_unregister_ip_masq_app(ip_masq_h225_app, 0)) IP_MASQ_H323_DEBUG("ip_masq_h225_done: H323: ERROR unloading support on port = %d\n", port_h225); else IP_MASQ_H323_DEBUG("ip_masq_h225_done: H323: unloaded support on port = %d\n", port_h225); if (h245registered) { IP_MASQ_H323_DEBUG("ip_masq_h225_done: removing the masq app entry\n"); netmeeting_unregister_ip_masq_app(ip_masq_h245_app, 1); h245registered=0; } return 0; } #ifdef MODULE int init_module(void) { IP_MASQ_H323_DEBUG("Init module\n"); /* CORITEL: DEBUG: */ masq_h245_app_debug=ip_masq_h245_app; if (ip_masq_h225_init() != 0) return -EIO; return 0; } void cleanup_module(void) { if (ip_masq_h225_done() != 0) IP_MASQ_H323_DEBUG("ip_masq_h225: can't remove module\n"); } #endif /* MODULE */