1 /* 2 * Copyright (C) 1998-2003 by Darren Reed 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * $Id: ip_rcmd_pxy.c,v 1.41.2.4 2005/02/04 10:22:55 darrenr Exp $ 7 * 8 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 9 * Use is subject to license terms. 10 * 11 * Simple RCMD transparent proxy for in-kernel use. For use with the NAT 12 * code. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #define IPF_RCMD_PROXY 18 19 20 int ippr_rcmd_init __P((void)); 21 void ippr_rcmd_fini __P((void)); 22 int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *)); 23 int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *)); 24 int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *)); 25 u_short ipf_rcmd_atoi __P((char *)); 26 int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *)); 27 28 static frentry_t rcmdfr; 29 30 int rcmd_proxy_init = 0; 31 32 33 /* 34 * RCMD application proxy initialization. 35 */ 36 int ippr_rcmd_init() 37 { 38 bzero((char *)&rcmdfr, sizeof(rcmdfr)); 39 rcmdfr.fr_ref = 1; 40 rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 41 MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock"); 42 rcmd_proxy_init = 1; 43 44 return 0; 45 } 46 47 48 void ippr_rcmd_fini() 49 { 50 if (rcmd_proxy_init == 1) { 51 MUTEX_DESTROY(&rcmdfr.fr_lock); 52 rcmd_proxy_init = 0; 53 } 54 } 55 56 57 /* 58 * Setup for a new RCMD proxy. 59 */ 60 int ippr_rcmd_new(fin, aps, nat) 61 fr_info_t *fin; 62 ap_session_t *aps; 63 nat_t *nat; 64 { 65 tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; 66 67 fin = fin; /* LINT */ 68 nat = nat; /* LINT */ 69 70 aps->aps_psiz = sizeof(u_32_t); 71 KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t)); 72 if (aps->aps_data == NULL) { 73 #ifdef IP_RCMD_PROXY_DEBUG 74 printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t)); 75 #endif 76 return -1; 77 } 78 *(u_32_t *)aps->aps_data = 0; 79 aps->aps_sport = tcp->th_sport; 80 aps->aps_dport = tcp->th_dport; 81 return 0; 82 } 83 84 85 /* 86 * ipf_rcmd_atoi - implement a simple version of atoi 87 */ 88 u_short ipf_rcmd_atoi(ptr) 89 char *ptr; 90 { 91 register char *s = ptr, c; 92 register u_short i = 0; 93 94 while (((c = *s++) != '\0') && ISDIGIT(c)) { 95 i *= 10; 96 i += c - '0'; 97 } 98 return i; 99 } 100 101 102 int ippr_rcmd_portmsg(fin, aps, nat) 103 fr_info_t *fin; 104 ap_session_t *aps; 105 nat_t *nat; 106 { 107 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 108 struct in_addr swip, swip2; 109 int off, dlen, nflags; 110 char portbuf[8], *s; 111 fr_info_t fi; 112 u_short sp; 113 nat_t *nat2; 114 ip_t *ip; 115 mb_t *m; 116 117 tcp = (tcphdr_t *)fin->fin_dp; 118 119 if (tcp->th_flags & TH_SYN) { 120 *(u_32_t *)aps->aps_data = htonl(ntohl(tcp->th_seq) + 1); 121 return 0; 122 } 123 124 if ((*(u_32_t *)aps->aps_data != 0) && 125 (tcp->th_seq != *(u_32_t *)aps->aps_data)) 126 return 0; 127 128 m = fin->fin_m; 129 ip = fin->fin_ip; 130 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 131 132 #ifdef __sgi 133 dlen = fin->fin_plen - off; 134 #else 135 dlen = MSGDSIZE(m) - off; 136 #endif 137 if (dlen <= 0) 138 return 0; 139 140 bzero(portbuf, sizeof(portbuf)); 141 COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf); 142 143 portbuf[sizeof(portbuf) - 1] = '\0'; 144 s = portbuf; 145 sp = ipf_rcmd_atoi(s); 146 if (sp == 0) { 147 #ifdef IP_RCMD_PROXY_DEBUG 148 printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n", 149 dlen, portbuf); 150 #endif 151 return 0; 152 } 153 154 /* 155 * Add skeleton NAT entry for connection which will come back the 156 * other way. 157 */ 158 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 159 fi.fin_flx |= FI_IGNORE; 160 fi.fin_data[0] = sp; 161 fi.fin_data[1] = 0; 162 if (nat->nat_dir == NAT_OUTBOUND) 163 nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 164 nat->nat_inip, nat->nat_oip); 165 else 166 nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 167 nat->nat_inip, nat->nat_oip); 168 if (nat2 == NULL) { 169 int slen; 170 171 slen = ip->ip_len; 172 ip->ip_len = fin->fin_hlen + sizeof(*tcp); 173 bzero((char *)tcp2, sizeof(*tcp2)); 174 tcp2->th_win = htons(8192); 175 tcp2->th_sport = htons(sp); 176 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 177 TCP_OFF_A(tcp2, 5); 178 tcp2->th_flags = TH_SYN; 179 fi.fin_dp = (char *)tcp2; 180 fi.fin_fr = &rcmdfr; 181 fi.fin_dlen = sizeof(*tcp2); 182 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 183 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 184 nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; 185 186 swip = ip->ip_src; 187 swip2 = ip->ip_dst; 188 189 if (nat->nat_dir == NAT_OUTBOUND) { 190 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 191 ip->ip_src = nat->nat_inip; 192 } else { 193 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 194 ip->ip_src = nat->nat_oip; 195 nflags |= NAT_NOTRULEPORT; 196 } 197 198 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); 199 200 if (nat2 != NULL) { 201 (void) nat_proto(&fi, nat2, IPN_TCP); 202 nat_update(&fi, nat2, nat2->nat_ptr); 203 fi.fin_ifp = NULL; 204 if (nat->nat_dir == NAT_INBOUND) { 205 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 206 ip->ip_dst = nat->nat_inip; 207 } 208 (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); 209 if (fi.fin_state != NULL) 210 fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 211 } 212 ip->ip_len = slen; 213 ip->ip_src = swip; 214 ip->ip_dst = swip2; 215 } 216 return 0; 217 } 218 219 220 int ippr_rcmd_out(fin, aps, nat) 221 fr_info_t *fin; 222 ap_session_t *aps; 223 nat_t *nat; 224 { 225 if (nat->nat_dir == NAT_OUTBOUND) 226 return ippr_rcmd_portmsg(fin, aps, nat); 227 return 0; 228 } 229 230 231 int ippr_rcmd_in(fin, aps, nat) 232 fr_info_t *fin; 233 ap_session_t *aps; 234 nat_t *nat; 235 { 236 if (nat->nat_dir == NAT_INBOUND) 237 return ippr_rcmd_portmsg(fin, aps, nat); 238 return 0; 239 } 240