Home | History | Annotate | Line # | Download | only in netinet
ip_raudio_pxy.c revision 1.1.1.2
      1      1.1  christos /*	$NetBSD: ip_raudio_pxy.c,v 1.1.1.2 2012/07/22 13:45:33 darrenr Exp $	*/
      2      1.1  christos 
      3      1.1  christos /*
      4  1.1.1.2   darrenr  * Copyright (C) 2012 by Darren Reed.
      5      1.1  christos  *
      6      1.1  christos  * See the IPFILTER.LICENCE file for details on licencing.
      7      1.1  christos  *
      8  1.1.1.2   darrenr  * $Id: ip_raudio_pxy.c,v 1.1.1.2 2012/07/22 13:45:33 darrenr Exp $
      9      1.1  christos  */
     10      1.1  christos 
     11      1.1  christos #define	IPF_RAUDIO_PROXY
     12      1.1  christos 
     13      1.1  christos 
     14      1.1  christos void ipf_p_raudio_main_load __P((void));
     15      1.1  christos void ipf_p_raudio_main_unload __P((void));
     16      1.1  christos int ipf_p_raudio_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
     17      1.1  christos int ipf_p_raudio_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
     18      1.1  christos int ipf_p_raudio_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
     19      1.1  christos 
     20      1.1  christos static	frentry_t	raudiofr;
     21      1.1  christos 
     22      1.1  christos int	raudio_proxy_init = 0;
     23      1.1  christos 
     24      1.1  christos 
     25      1.1  christos /*
     26      1.1  christos  * Real Audio application proxy initialization.
     27      1.1  christos  */
     28      1.1  christos void
     29      1.1  christos ipf_p_raudio_main_load()
     30      1.1  christos {
     31      1.1  christos 	bzero((char *)&raudiofr, sizeof(raudiofr));
     32      1.1  christos 	raudiofr.fr_ref = 1;
     33      1.1  christos 	raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
     34      1.1  christos 	MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock");
     35      1.1  christos 	raudio_proxy_init = 1;
     36      1.1  christos }
     37      1.1  christos 
     38      1.1  christos 
     39      1.1  christos void
     40      1.1  christos ipf_p_raudio_main_unload()
     41      1.1  christos {
     42      1.1  christos 	if (raudio_proxy_init == 1) {
     43      1.1  christos 		MUTEX_DESTROY(&raudiofr.fr_lock);
     44      1.1  christos 		raudio_proxy_init = 0;
     45      1.1  christos 	}
     46      1.1  christos }
     47      1.1  christos 
     48      1.1  christos 
     49      1.1  christos /*
     50      1.1  christos  * Setup for a new proxy to handle Real Audio.
     51      1.1  christos  */
     52      1.1  christos int
     53      1.1  christos ipf_p_raudio_new(arg, fin, aps, nat)
     54      1.1  christos 	void *arg;
     55      1.1  christos 	fr_info_t *fin;
     56      1.1  christos 	ap_session_t *aps;
     57      1.1  christos 	nat_t *nat;
     58      1.1  christos {
     59      1.1  christos 	raudio_t *rap;
     60      1.1  christos 
     61  1.1.1.2   darrenr 	nat = nat;	/* LINT */
     62  1.1.1.2   darrenr 
     63  1.1.1.2   darrenr 	if (fin->fin_v != 4)
     64  1.1.1.2   darrenr 		return -1;
     65  1.1.1.2   darrenr 
     66      1.1  christos 	KMALLOCS(aps->aps_data, void *, sizeof(raudio_t));
     67      1.1  christos 	if (aps->aps_data == NULL)
     68      1.1  christos 		return -1;
     69      1.1  christos 
     70      1.1  christos 	bzero(aps->aps_data, sizeof(raudio_t));
     71      1.1  christos 	rap = aps->aps_data;
     72      1.1  christos 	aps->aps_psiz = sizeof(raudio_t);
     73      1.1  christos 	rap->rap_mode = RAP_M_TCP;	/* default is for TCP */
     74      1.1  christos 	return 0;
     75      1.1  christos }
     76      1.1  christos 
     77      1.1  christos 
     78      1.1  christos 
     79      1.1  christos int
     80      1.1  christos ipf_p_raudio_out(arg, fin, aps, nat)
     81      1.1  christos 	void *arg;
     82      1.1  christos 	fr_info_t *fin;
     83      1.1  christos 	ap_session_t *aps;
     84      1.1  christos 	nat_t *nat;
     85      1.1  christos {
     86      1.1  christos 	raudio_t *rap = aps->aps_data;
     87      1.1  christos 	unsigned char membuf[512 + 1], *s;
     88      1.1  christos 	u_short id = 0;
     89      1.1  christos 	tcphdr_t *tcp;
     90      1.1  christos 	int off, dlen;
     91      1.1  christos 	int len = 0;
     92      1.1  christos 	mb_t *m;
     93      1.1  christos 
     94      1.1  christos 	nat = nat;	/* LINT */
     95      1.1  christos 
     96      1.1  christos 	/*
     97      1.1  christos 	 * If we've already processed the start messages, then nothing left
     98      1.1  christos 	 * for the proxy to do.
     99      1.1  christos 	 */
    100      1.1  christos 	if (rap->rap_eos == 1)
    101      1.1  christos 		return 0;
    102      1.1  christos 
    103      1.1  christos 	m = fin->fin_m;
    104      1.1  christos 	tcp = (tcphdr_t *)fin->fin_dp;
    105      1.1  christos 	off = (char *)tcp - (char *)fin->fin_ip;
    106      1.1  christos 	off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
    107      1.1  christos 
    108      1.1  christos #ifdef __sgi
    109      1.1  christos 	dlen = fin->fin_plen - off;
    110      1.1  christos #else
    111      1.1  christos 	dlen = MSGDSIZE(m) - off;
    112      1.1  christos #endif
    113      1.1  christos 	if (dlen <= 0)
    114      1.1  christos 		return 0;
    115      1.1  christos 
    116      1.1  christos 	if (dlen > sizeof(membuf))
    117      1.1  christos 		dlen = sizeof(membuf);
    118      1.1  christos 
    119      1.1  christos 	bzero((char *)membuf, sizeof(membuf));
    120      1.1  christos 	COPYDATA(m, off, dlen, (char *)membuf);
    121      1.1  christos 	/*
    122      1.1  christos 	 * In all the startup parsing, ensure that we don't go outside
    123      1.1  christos 	 * the packet buffer boundary.
    124      1.1  christos 	 */
    125      1.1  christos 	/*
    126      1.1  christos 	 * Look for the start of connection "PNA" string if not seen yet.
    127      1.1  christos 	 */
    128      1.1  christos 	if (rap->rap_seenpna == 0) {
    129      1.1  christos 		s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen);
    130      1.1  christos 		if (s == NULL)
    131      1.1  christos 			return 0;
    132      1.1  christos 		s += 3;
    133      1.1  christos 		rap->rap_seenpna = 1;
    134      1.1  christos 	} else
    135      1.1  christos 		s = membuf;
    136      1.1  christos 
    137      1.1  christos 	/*
    138      1.1  christos 	 * Directly after the PNA will be the version number of this
    139      1.1  christos 	 * connection.
    140      1.1  christos 	 */
    141      1.1  christos 	if (rap->rap_seenpna == 1 && rap->rap_seenver == 0) {
    142      1.1  christos 		if ((s + 1) - membuf < dlen) {
    143      1.1  christos 			rap->rap_version = (*s << 8) | *(s + 1);
    144      1.1  christos 			s += 2;
    145      1.1  christos 			rap->rap_seenver = 1;
    146      1.1  christos 		} else
    147      1.1  christos 			return 0;
    148      1.1  christos 	}
    149      1.1  christos 
    150      1.1  christos 	/*
    151      1.1  christos 	 * Now that we've been past the PNA and version number, we're into the
    152      1.1  christos 	 * startup messages block.  This ends when a message with an ID of 0.
    153      1.1  christos 	 */
    154      1.1  christos 	while ((rap->rap_eos == 0) && ((s + 1) - membuf < dlen)) {
    155      1.1  christos 		if (rap->rap_gotid == 0) {
    156      1.1  christos 			id = (*s << 8) | *(s + 1);
    157      1.1  christos 			s += 2;
    158      1.1  christos 			rap->rap_gotid = 1;
    159      1.1  christos 			if (id == RA_ID_END) {
    160      1.1  christos 				rap->rap_eos = 1;
    161      1.1  christos 				break;
    162      1.1  christos 			}
    163      1.1  christos 		} else if (rap->rap_gotlen == 0) {
    164      1.1  christos 			len = (*s << 8) | *(s + 1);
    165      1.1  christos 			s += 2;
    166      1.1  christos 			rap->rap_gotlen = 1;
    167      1.1  christos 		}
    168      1.1  christos 
    169      1.1  christos 		if (rap->rap_gotid == 1 && rap->rap_gotlen == 1) {
    170      1.1  christos 			if (id == RA_ID_UDP) {
    171      1.1  christos 				rap->rap_mode &= ~RAP_M_TCP;
    172      1.1  christos 				rap->rap_mode |= RAP_M_UDP;
    173      1.1  christos 				rap->rap_plport = (*s << 8) | *(s + 1);
    174      1.1  christos 			} else if (id == RA_ID_ROBUST) {
    175      1.1  christos 				rap->rap_mode |= RAP_M_ROBUST;
    176      1.1  christos 				rap->rap_prport = (*s << 8) | *(s + 1);
    177      1.1  christos 			}
    178      1.1  christos 			s += len;
    179      1.1  christos 			rap->rap_gotlen = 0;
    180      1.1  christos 			rap->rap_gotid = 0;
    181      1.1  christos 		}
    182      1.1  christos 	}
    183      1.1  christos 	return 0;
    184      1.1  christos }
    185      1.1  christos 
    186      1.1  christos 
    187      1.1  christos int
    188      1.1  christos ipf_p_raudio_in(arg, fin, aps, nat)
    189      1.1  christos 	void *arg;
    190      1.1  christos 	fr_info_t *fin;
    191      1.1  christos 	ap_session_t *aps;
    192      1.1  christos 	nat_t *nat;
    193      1.1  christos {
    194      1.1  christos 	unsigned char membuf[IPF_MAXPORTLEN + 1], *s;
    195      1.1  christos 	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
    196      1.1  christos 	raudio_t *rap = aps->aps_data;
    197      1.1  christos 	ipf_main_softc_t *softc;
    198      1.1  christos 	ipf_nat_softc_t *softn;
    199      1.1  christos 	struct in_addr swa, swb;
    200      1.1  christos 	int off, dlen, slen;
    201      1.1  christos 	int a1, a2, a3, a4;
    202      1.1  christos 	u_short sp, dp;
    203      1.1  christos 	fr_info_t fi;
    204      1.1  christos 	tcp_seq seq;
    205      1.1  christos 	nat_t *nat2;
    206      1.1  christos 	u_char swp;
    207      1.1  christos 	ip_t *ip;
    208      1.1  christos 	mb_t *m;
    209      1.1  christos 
    210      1.1  christos 	softc = fin->fin_main_soft;
    211      1.1  christos 	softn = softc->ipf_nat_soft;
    212      1.1  christos 	/*
    213      1.1  christos 	 * Wait until we've seen the end of the start messages and even then
    214      1.1  christos 	 * only proceed further if we're using UDP.  If they want to use TCP
    215      1.1  christos 	 * then data is sent back on the same channel that is already open.
    216      1.1  christos 	 */
    217      1.1  christos 	if (rap->rap_sdone != 0)
    218      1.1  christos 		return 0;
    219      1.1  christos 
    220      1.1  christos 	m = fin->fin_m;
    221      1.1  christos 	tcp = (tcphdr_t *)fin->fin_dp;
    222      1.1  christos 	off = (char *)tcp - (char *)fin->fin_ip;
    223      1.1  christos 	off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
    224      1.1  christos 
    225      1.1  christos #ifdef __sgi
    226      1.1  christos 	dlen = fin->fin_plen - off;
    227      1.1  christos #else
    228      1.1  christos 	dlen = MSGDSIZE(m) - off;
    229      1.1  christos #endif
    230      1.1  christos 	if (dlen <= 0)
    231      1.1  christos 		return 0;
    232      1.1  christos 
    233      1.1  christos 	if (dlen > sizeof(membuf))
    234      1.1  christos 		dlen = sizeof(membuf);
    235      1.1  christos 
    236      1.1  christos 	bzero((char *)membuf, sizeof(membuf));
    237      1.1  christos 	COPYDATA(m, off, dlen, (char *)membuf);
    238      1.1  christos 
    239      1.1  christos 	seq = ntohl(tcp->th_seq);
    240      1.1  christos 	/*
    241      1.1  christos 	 * Check to see if the data in this packet is of interest to us.
    242      1.1  christos 	 * We only care for the first 19 bytes coming back from the server.
    243      1.1  christos 	 */
    244      1.1  christos 	if (rap->rap_sseq == 0) {
    245      1.1  christos 		s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen);
    246      1.1  christos 		if (s == NULL)
    247      1.1  christos 			return 0;
    248      1.1  christos 		a1 = s - membuf;
    249      1.1  christos 		dlen -= a1;
    250      1.1  christos 		a1 = 0;
    251      1.1  christos 		rap->rap_sseq = seq;
    252      1.1  christos 		a2 = MIN(dlen, sizeof(rap->rap_svr));
    253      1.1  christos 	} else if (seq <= rap->rap_sseq + sizeof(rap->rap_svr)) {
    254      1.1  christos 		/*
    255      1.1  christos 		 * seq # which is the start of data and from that the offset
    256      1.1  christos 		 * into the buffer array.
    257      1.1  christos 		 */
    258      1.1  christos 		a1 = seq - rap->rap_sseq;
    259      1.1  christos 		a2 = MIN(dlen, sizeof(rap->rap_svr));
    260      1.1  christos 		a2 -= a1;
    261      1.1  christos 		s = membuf;
    262      1.1  christos 	} else
    263      1.1  christos 		return 0;
    264      1.1  christos 
    265      1.1  christos 	for (a3 = a1, a4 = a2; (a4 > 0) && (a3 < 19) && (a3 >= 0); a4--,a3++) {
    266      1.1  christos 		rap->rap_sbf |= (1 << a3);
    267      1.1  christos 		rap->rap_svr[a3] = *s++;
    268      1.1  christos 	}
    269      1.1  christos 
    270      1.1  christos 	if ((rap->rap_sbf != 0x7ffff) || (!rap->rap_eos))	/* 19 bits */
    271      1.1  christos 		return 0;
    272      1.1  christos 	rap->rap_sdone = 1;
    273      1.1  christos 
    274      1.1  christos 	s = (u_char *)rap->rap_svr + 11;
    275      1.1  christos 	if (((*s << 8) | *(s + 1)) == RA_ID_ROBUST) {
    276      1.1  christos 		s += 2;
    277      1.1  christos 		rap->rap_srport = (*s << 8) | *(s + 1);
    278      1.1  christos 	}
    279      1.1  christos 
    280      1.1  christos 	ip = fin->fin_ip;
    281      1.1  christos 	swp = ip->ip_p;
    282      1.1  christos 	swa = ip->ip_src;
    283      1.1  christos 	swb = ip->ip_dst;
    284      1.1  christos 
    285      1.1  christos 	ip->ip_p = IPPROTO_UDP;
    286      1.1  christos 	ip->ip_src = nat->nat_ndstip;
    287      1.1  christos 	ip->ip_dst = nat->nat_odstip;
    288      1.1  christos 
    289      1.1  christos 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
    290      1.1  christos 	bzero((char *)tcp2, sizeof(*tcp2));
    291      1.1  christos 	TCP_OFF_A(tcp2, 5);
    292      1.1  christos 	fi.fin_flx |= FI_IGNORE;
    293      1.1  christos 	fi.fin_dp = (char *)tcp2;
    294      1.1  christos 	fi.fin_fr = &raudiofr;
    295      1.1  christos 	fi.fin_dlen = sizeof(*tcp2);
    296      1.1  christos 	fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
    297      1.1  christos 	tcp2->th_win = htons(8192);
    298      1.1  christos 	slen = ip->ip_len;
    299      1.1  christos 	ip->ip_len = htons(fin->fin_hlen + sizeof(*tcp));
    300      1.1  christos 
    301      1.1  christos 	if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) &&
    302      1.1  christos 	    (rap->rap_srport != 0)) {
    303      1.1  christos 		dp = rap->rap_srport;
    304      1.1  christos 		sp = rap->rap_prport;
    305      1.1  christos 		tcp2->th_sport = htons(sp);
    306      1.1  christos 		tcp2->th_dport = htons(dp);
    307      1.1  christos 		fi.fin_data[0] = dp;
    308      1.1  christos 		fi.fin_data[1] = sp;
    309      1.1  christos 		fi.fin_out = 0;
    310      1.1  christos 		MUTEX_ENTER(&softn->ipf_nat_new);
    311      1.1  christos 		nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
    312      1.1  christos 			       NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT),
    313      1.1  christos 			       NAT_OUTBOUND);
    314      1.1  christos 		MUTEX_EXIT(&softn->ipf_nat_new);
    315      1.1  christos 		if (nat2 != NULL) {
    316      1.1  christos 			(void) ipf_nat_proto(&fi, nat2, IPN_UDP);
    317      1.1  christos 			MUTEX_ENTER(&nat2->nat_lock);
    318      1.1  christos 			ipf_nat_update(&fi, nat2);
    319      1.1  christos 			MUTEX_EXIT(&nat2->nat_lock);
    320      1.1  christos 
    321      1.1  christos 			(void) ipf_state_add(softc, &fi, NULL,
    322      1.1  christos 					     (sp ? 0 : SI_W_SPORT));
    323      1.1  christos 		}
    324      1.1  christos 	}
    325      1.1  christos 
    326      1.1  christos 	if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) {
    327      1.1  christos 		sp = rap->rap_plport;
    328      1.1  christos 		tcp2->th_sport = htons(sp);
    329      1.1  christos 		tcp2->th_dport = 0; /* XXX - don't specify remote port */
    330      1.1  christos 		fi.fin_data[0] = sp;
    331      1.1  christos 		fi.fin_data[1] = 0;
    332      1.1  christos 		fi.fin_out = 1;
    333      1.1  christos 		MUTEX_ENTER(&softn->ipf_nat_new);
    334      1.1  christos 		nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
    335      1.1  christos 			       NAT_SLAVE|IPN_UDP|SI_W_DPORT,
    336      1.1  christos 			       NAT_OUTBOUND);
    337      1.1  christos 		MUTEX_EXIT(&softn->ipf_nat_new);
    338      1.1  christos 		if (nat2 != NULL) {
    339      1.1  christos 			(void) ipf_nat_proto(&fi, nat2, IPN_UDP);
    340      1.1  christos 			MUTEX_ENTER(&nat2->nat_lock);
    341      1.1  christos 			ipf_nat_update(&fi, nat2);
    342      1.1  christos 			MUTEX_EXIT(&nat2->nat_lock);
    343      1.1  christos 
    344      1.1  christos 			(void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT);
    345      1.1  christos 		}
    346      1.1  christos 	}
    347      1.1  christos 
    348      1.1  christos 	ip->ip_p = swp;
    349      1.1  christos 	ip->ip_len = slen;
    350      1.1  christos 	ip->ip_src = swa;
    351      1.1  christos 	ip->ip_dst = swb;
    352      1.1  christos 	return 0;
    353      1.1  christos }
    354