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 2007 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 typedef struct ifs_rcmdpxy { 20 frentry_t rcmdfr; 21 int rcmd_proxy_init; 22 } ifs_rcmdpxy_t; 23 24 int ippr_rcmd_init __P((void **, ipf_stack_t *)); 25 void ippr_rcmd_fini __P((void **, ipf_stack_t *)); 26 int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 27 int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 28 int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 29 u_short ipf_rcmd_atoi __P((char *)); 30 int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *, ifs_rcmdpxy_t *)); 31 32 /* 33 * RCMD application proxy initialization. 34 */ 35 /*ARGSUSED*/ 36 int ippr_rcmd_init(private, ifs) 37 void **private; 38 ipf_stack_t *ifs; 39 { 40 ifs_rcmdpxy_t *ifsrcmd; 41 42 KMALLOC(ifsrcmd, ifs_rcmdpxy_t *); 43 if (ifsrcmd == NULL) 44 return -1; 45 46 bzero((char *)&ifsrcmd->rcmdfr, sizeof(ifsrcmd->rcmdfr)); 47 ifsrcmd->rcmdfr.fr_ref = 1; 48 ifsrcmd->rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 49 MUTEX_INIT(&ifsrcmd->rcmdfr.fr_lock, "RCMD proxy rule lock"); 50 ifsrcmd->rcmd_proxy_init = 1; 51 52 *private = (void *)ifsrcmd; 53 54 return 0; 55 } 56 57 58 /*ARGSUSED*/ 59 void ippr_rcmd_fini(private, ifs) 60 void **private; 61 ipf_stack_t *ifs; 62 { 63 ifs_rcmdpxy_t *ifsrcmd = *((ifs_rcmdpxy_t **)private); 64 65 if (ifsrcmd->rcmd_proxy_init == 1) { 66 MUTEX_DESTROY(&ifsrcmd->rcmdfr.fr_lock); 67 ifsrcmd->rcmd_proxy_init = 0; 68 } 69 70 KFREE(ifsrcmd); 71 *private = NULL; 72 } 73 74 75 /* 76 * Setup for a new RCMD proxy. 77 */ 78 /*ARGSUSED*/ 79 int ippr_rcmd_new(fin, aps, nat, private) 80 fr_info_t *fin; 81 ap_session_t *aps; 82 nat_t *nat; 83 void *private; 84 { 85 tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; 86 87 fin = fin; /* LINT */ 88 nat = nat; /* LINT */ 89 90 aps->aps_psiz = sizeof(u_32_t); 91 KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t)); 92 if (aps->aps_data == NULL) { 93 #ifdef IP_RCMD_PROXY_DEBUG 94 printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t)); 95 #endif 96 return -1; 97 } 98 *(u_32_t *)aps->aps_data = 0; 99 aps->aps_sport = tcp->th_sport; 100 aps->aps_dport = tcp->th_dport; 101 return 0; 102 } 103 104 105 /* 106 * ipf_rcmd_atoi - implement a simple version of atoi 107 */ 108 u_short ipf_rcmd_atoi(ptr) 109 char *ptr; 110 { 111 register char *s = ptr, c; 112 register u_short i = 0; 113 114 while (((c = *s++) != '\0') && ISDIGIT(c)) { 115 i *= 10; 116 i += c - '0'; 117 } 118 return i; 119 } 120 121 122 int ippr_rcmd_portmsg(fin, aps, nat, ifsrcmd) 123 fr_info_t *fin; 124 ap_session_t *aps; 125 nat_t *nat; 126 ifs_rcmdpxy_t *ifsrcmd; 127 { 128 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 129 struct in_addr swip, swip2; 130 int off, dlen, nflags; 131 char portbuf[8], *s; 132 fr_info_t fi; 133 u_short sp; 134 nat_t *nat2; 135 ip_t *ip; 136 mb_t *m; 137 ipf_stack_t *ifs = fin->fin_ifs; 138 139 tcp = (tcphdr_t *)fin->fin_dp; 140 141 if (tcp->th_flags & TH_SYN) { 142 *(u_32_t *)aps->aps_data = htonl(ntohl(tcp->th_seq) + 1); 143 return 0; 144 } 145 146 if ((*(u_32_t *)aps->aps_data != 0) && 147 (tcp->th_seq != *(u_32_t *)aps->aps_data)) 148 return 0; 149 150 m = fin->fin_m; 151 ip = fin->fin_ip; 152 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 153 154 #ifdef __sgi 155 dlen = fin->fin_plen - off; 156 #else 157 dlen = MSGDSIZE(m) - off; 158 #endif 159 if (dlen <= 0) 160 return 0; 161 162 bzero(portbuf, sizeof(portbuf)); 163 COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf); 164 165 portbuf[sizeof(portbuf) - 1] = '\0'; 166 s = portbuf; 167 sp = ipf_rcmd_atoi(s); 168 if (sp == 0) { 169 #ifdef IP_RCMD_PROXY_DEBUG 170 printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n", 171 dlen, portbuf); 172 #endif 173 return 0; 174 } 175 176 /* 177 * Add skeleton NAT entry for connection which will come back the 178 * other way. 179 */ 180 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 181 fi.fin_flx |= FI_IGNORE; 182 fi.fin_data[0] = sp; 183 fi.fin_data[1] = 0; 184 if (nat->nat_dir == NAT_OUTBOUND) 185 nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 186 nat->nat_inip, nat->nat_oip); 187 else 188 nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 189 nat->nat_inip, nat->nat_oip); 190 if (nat2 == NULL) { 191 int slen; 192 193 slen = ip->ip_len; 194 ip->ip_len = fin->fin_hlen + sizeof(*tcp); 195 bzero((char *)tcp2, sizeof(*tcp2)); 196 tcp2->th_win = htons(8192); 197 tcp2->th_sport = htons(sp); 198 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 199 TCP_OFF_A(tcp2, 5); 200 tcp2->th_flags = TH_SYN; 201 fi.fin_dp = (char *)tcp2; 202 fi.fin_fr = &ifsrcmd->rcmdfr; 203 fi.fin_dlen = sizeof(*tcp2); 204 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 205 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 206 nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; 207 208 swip = ip->ip_src; 209 swip2 = ip->ip_dst; 210 211 if (nat->nat_dir == NAT_OUTBOUND) { 212 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 213 ip->ip_src = nat->nat_inip; 214 } else { 215 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 216 ip->ip_src = nat->nat_oip; 217 nflags |= NAT_NOTRULEPORT; 218 } 219 220 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); 221 222 if (nat2 != NULL) { 223 (void) nat_proto(&fi, nat2, IPN_TCP); 224 nat_update(&fi, nat2, nat2->nat_ptr); 225 fi.fin_ifp = NULL; 226 if (nat->nat_dir == NAT_INBOUND) { 227 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 228 ip->ip_dst = nat->nat_inip; 229 } 230 (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); 231 if (fi.fin_state != NULL) 232 fr_statederef(&fi, (ipstate_t **)&fi.fin_state, ifs); 233 } 234 ip->ip_len = slen; 235 ip->ip_src = swip; 236 ip->ip_dst = swip2; 237 } 238 return 0; 239 } 240 241 242 int ippr_rcmd_out(fin, aps, nat, private) 243 fr_info_t *fin; 244 ap_session_t *aps; 245 nat_t *nat; 246 void *private; 247 { 248 if (nat->nat_dir == NAT_OUTBOUND) 249 return ippr_rcmd_portmsg(fin, aps, nat, (ifs_rcmdpxy_t *)private); 250 return 0; 251 } 252 253 254 int ippr_rcmd_in(fin, aps, nat, private) 255 fr_info_t *fin; 256 ap_session_t *aps; 257 nat_t *nat; 258 void *private; 259 { 260 if (nat->nat_dir == NAT_INBOUND) 261 return ippr_rcmd_portmsg(fin, aps, nat, (ifs_rcmdpxy_t *)private); 262 return 0; 263 } 264