1 /* 2 * Copyright (C) 2012 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * $Id: ip_tftp_pxy.c,v 1.1.2.9 2012/07/22 08:04:23 darren_r Exp $ 7 */ 8 9 #define IPF_TFTP_PROXY 10 11 typedef struct ipf_tftp_softc_s { 12 int ipf_p_tftp_readonly; 13 ipftuneable_t *ipf_p_tftp_tune; 14 } ipf_tftp_softc_t; 15 16 int ipf_p_tftp_backchannel(fr_info_t *, ap_session_t *, nat_t *); 17 int ipf_p_tftp_client(ipf_tftp_softc_t *, fr_info_t *, ap_session_t *, 18 nat_t *); 19 int ipf_p_tftp_in(void *, fr_info_t *, ap_session_t *, nat_t *); 20 void ipf_p_tftp_main_load(void); 21 void ipf_p_tftp_main_unload(void); 22 int ipf_p_tftp_new(void *, fr_info_t *, ap_session_t *, nat_t *); 23 void ipf_p_tftp_del(ipf_main_softc_t *, ap_session_t *); 24 int ipf_p_tftp_out(void *, fr_info_t *, ap_session_t *, nat_t *); 25 int ipf_p_tftp_server(ipf_tftp_softc_t *, fr_info_t *, ap_session_t *, 26 nat_t *); 27 void *ipf_p_tftp_soft_create(ipf_main_softc_t *); 28 void ipf_p_tftp_soft_destroy(ipf_main_softc_t *, void *); 29 30 static frentry_t tftpfr; 31 static int tftp_proxy_init = 0; 32 33 typedef enum tftp_cmd_e { 34 TFTP_CMD_READ = 1, 35 TFTP_CMD_WRITE = 2, 36 TFTP_CMD_DATA = 3, 37 TFTP_CMD_ACK = 4, 38 TFTP_CMD_ERROR = 5 39 } tftp_cmd_t; 40 41 typedef struct tftpinfo { 42 tftp_cmd_t ti_lastcmd; 43 int ti_nextblk; 44 int ti_lastblk; 45 int ti_lasterror; 46 char ti_filename[80]; 47 ipnat_t *ti_rule; 48 } tftpinfo_t; 49 50 static ipftuneable_t ipf_tftp_tuneables[] = { 51 { { (void *)offsetof(ipf_tftp_softc_t, ipf_p_tftp_readonly) }, 52 "tftp_read_only", 0, 1, 53 stsizeof(ipf_tftp_softc_t, ipf_p_tftp_readonly), 54 0, NULL, NULL }, 55 { { NULL }, NULL, 0, 0, 0, 0, NULL, NULL } 56 }; 57 58 59 /* 60 * TFTP application proxy initialization. 61 */ 62 void 63 ipf_p_tftp_main_load(void) 64 { 65 66 bzero((char *)&tftpfr, sizeof(tftpfr)); 67 tftpfr.fr_ref = 1; 68 tftpfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 69 MUTEX_INIT(&tftpfr.fr_lock, "TFTP proxy rule lock"); 70 tftp_proxy_init = 1; 71 } 72 73 74 void 75 ipf_p_tftp_main_unload(void) 76 { 77 78 if (tftp_proxy_init == 1) { 79 MUTEX_DESTROY(&tftpfr.fr_lock); 80 tftp_proxy_init = 0; 81 } 82 } 83 84 85 void * 86 ipf_p_tftp_soft_create(ipf_main_softc_t *softc) 87 { 88 ipf_tftp_softc_t *softt; 89 90 KMALLOC(softt, ipf_tftp_softc_t *); 91 if (softt == NULL) 92 return (NULL); 93 94 bzero((char *)softt, sizeof(*softt)); 95 96 softt->ipf_p_tftp_tune = ipf_tune_array_copy(softt, 97 sizeof(ipf_tftp_tuneables), 98 ipf_tftp_tuneables); 99 if (softt->ipf_p_tftp_tune == NULL) { 100 ipf_p_tftp_soft_destroy(softc, softt); 101 return (NULL); 102 } 103 if (ipf_tune_array_link(softc, softt->ipf_p_tftp_tune) == -1) { 104 ipf_p_tftp_soft_destroy(softc, softt); 105 return (NULL); 106 } 107 108 softt->ipf_p_tftp_readonly = 1; 109 110 return (softt); 111 } 112 113 114 void 115 ipf_p_tftp_soft_destroy(ipf_main_softc_t *softc, void *arg) 116 { 117 ipf_tftp_softc_t *softt = arg; 118 119 if (softt->ipf_p_tftp_tune != NULL) { 120 ipf_tune_array_unlink(softc, softt->ipf_p_tftp_tune); 121 KFREES(softt->ipf_p_tftp_tune, sizeof(ipf_tftp_tuneables)); 122 softt->ipf_p_tftp_tune = NULL; 123 } 124 125 KFREE(softt); 126 } 127 128 129 int 130 ipf_p_tftp_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 131 { 132 ipf_tftp_softc_t *softt = arg; 133 134 fin->fin_flx |= FI_NOWILD; 135 if (nat->nat_dir == NAT_OUTBOUND) 136 return (ipf_p_tftp_client(softt, fin, aps, nat)); 137 return (ipf_p_tftp_server(softt, fin, aps, nat)); 138 } 139 140 141 int 142 ipf_p_tftp_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 143 { 144 ipf_tftp_softc_t *softt = arg; 145 146 fin->fin_flx |= FI_NOWILD; 147 if (nat->nat_dir == NAT_INBOUND) 148 return (ipf_p_tftp_client(softt, fin, aps, nat)); 149 return (ipf_p_tftp_server(softt, fin, aps, nat)); 150 } 151 152 153 int 154 ipf_p_tftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 155 { 156 udphdr_t *udp; 157 tftpinfo_t *ti; 158 ipnat_t *ipn; 159 ipnat_t *np; 160 int size; 161 162 fin = fin; /* LINT */ 163 164 np = nat->nat_ptr; 165 size = np->in_size; 166 167 KMALLOC(ti, tftpinfo_t *); 168 if (ti == NULL) 169 return (-1); 170 KMALLOCS(ipn, ipnat_t *, size); 171 if (ipn == NULL) { 172 KFREE(ti); 173 return (-1); 174 } 175 176 aps->aps_data = ti; 177 aps->aps_psiz = sizeof(*ti); 178 bzero((char *)ti, sizeof(*ti)); 179 bzero((char *)ipn, size); 180 ti->ti_rule = ipn; 181 182 udp = (udphdr_t *)fin->fin_dp; 183 aps->aps_sport = udp->uh_sport; 184 aps->aps_dport = udp->uh_dport; 185 186 ipn->in_size = size; 187 ipn->in_apr = NULL; 188 ipn->in_use = 1; 189 ipn->in_hits = 1; 190 ipn->in_ippip = 1; 191 ipn->in_pr[0] = IPPROTO_UDP; 192 ipn->in_pr[1] = IPPROTO_UDP; 193 ipn->in_ifps[0] = nat->nat_ifps[0]; 194 ipn->in_ifps[1] = nat->nat_ifps[1]; 195 ipn->in_v[0] = nat->nat_ptr->in_v[1]; 196 ipn->in_v[1] = nat->nat_ptr->in_v[0]; 197 ipn->in_flags = IPN_UDP|IPN_FIXEDDPORT|IPN_PROXYRULE; 198 199 ipn->in_nsrcip6 = nat->nat_odst6; 200 ipn->in_osrcip6 = nat->nat_ndst6; 201 202 if ((np->in_redir & NAT_REDIRECT) != 0) { 203 ipn->in_redir = NAT_MAP; 204 if (ipn->in_v[0] == 4) { 205 ipn->in_snip = ntohl(nat->nat_odstaddr); 206 ipn->in_dnip = ntohl(nat->nat_nsrcaddr); 207 } else { 208 #ifdef USE_INET6 209 ipn->in_snip6 = nat->nat_odst6; 210 ipn->in_dnip6 = nat->nat_nsrc6; 211 #endif 212 } 213 ipn->in_ndstip6 = nat->nat_nsrc6; 214 ipn->in_odstip6 = nat->nat_osrc6; 215 } else { 216 ipn->in_redir = NAT_REDIRECT; 217 if (ipn->in_v[0] == 4) { 218 ipn->in_snip = ntohl(nat->nat_odstaddr); 219 ipn->in_dnip = ntohl(nat->nat_osrcaddr); 220 } else { 221 #ifdef USE_INET6 222 ipn->in_snip6 = nat->nat_odst6; 223 ipn->in_dnip6 = nat->nat_osrc6; 224 #endif 225 } 226 ipn->in_ndstip6 = nat->nat_osrc6; 227 ipn->in_odstip6 = nat->nat_nsrc6; 228 } 229 ipn->in_odport = htons(fin->fin_sport); 230 ipn->in_ndport = htons(fin->fin_sport); 231 232 IP6_SETONES(&ipn->in_osrcmsk6); 233 IP6_SETONES(&ipn->in_nsrcmsk6); 234 IP6_SETONES(&ipn->in_odstmsk6); 235 IP6_SETONES(&ipn->in_ndstmsk6); 236 MUTEX_INIT(&ipn->in_lock, "tftp proxy NAT rule"); 237 238 ipn->in_namelen = np->in_namelen; 239 bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen); 240 ipn->in_ifnames[0] = np->in_ifnames[0]; 241 ipn->in_ifnames[1] = np->in_ifnames[1]; 242 243 ti->ti_lastcmd = 0; 244 245 return (0); 246 } 247 248 249 void 250 ipf_p_tftp_del(ipf_main_softc_t *softc, ap_session_t *aps) 251 { 252 tftpinfo_t *tftp; 253 254 tftp = aps->aps_data; 255 if (tftp != NULL) { 256 tftp->ti_rule->in_flags |= IPN_DELETE; 257 ipf_nat_rule_deref(softc, &tftp->ti_rule); 258 } 259 } 260 261 262 /* 263 * Setup for a new TFTP proxy. 264 */ 265 int 266 ipf_p_tftp_backchannel(fr_info_t *fin, ap_session_t *aps, nat_t *nat) 267 { 268 ipf_main_softc_t *softc = fin->fin_main_soft; 269 #ifdef USE_MUTEXES 270 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 271 #endif 272 #ifdef USE_INET6 273 i6addr_t swip6, sw2ip6; 274 ip6_t *ip6; 275 #endif 276 struct in_addr swip, sw2ip; 277 tftpinfo_t *ti; 278 udphdr_t udp; 279 fr_info_t fi; 280 u_short slen = 0; /* silence gcc */ 281 nat_t *nat2; 282 int nflags; 283 ip_t *ip; 284 int dir; 285 286 ti = aps->aps_data; 287 /* 288 * Add skeleton NAT entry for connection which will come back the 289 * other way. 290 */ 291 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 292 fi.fin_flx |= FI_IGNORE; 293 fi.fin_data[1] = 0; 294 295 bzero((char *)&udp, sizeof(udp)); 296 udp.uh_sport = 0; /* XXX - don't specify remote port */ 297 udp.uh_dport = ti->ti_rule->in_ndport; 298 udp.uh_ulen = htons(sizeof(udp)); 299 udp.uh_sum = 0; 300 301 fi.fin_fr = &tftpfr; 302 fi.fin_dp = (char *)&udp; 303 fi.fin_sport = 0; 304 fi.fin_dport = ntohs(ti->ti_rule->in_ndport); 305 fi.fin_dlen = sizeof(udp); 306 fi.fin_plen = fi.fin_hlen + sizeof(udp); 307 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 308 nflags = NAT_SLAVE|IPN_UDP|SI_W_SPORT; 309 #ifdef USE_INET6 310 ip6 = (ip6_t *)fin->fin_ip; 311 #endif 312 ip = fin->fin_ip; 313 sw2ip.s_addr = 0; 314 swip.s_addr = 0; 315 316 fi.fin_src6 = nat->nat_ndst6; 317 fi.fin_dst6 = nat->nat_nsrc6; 318 if (nat->nat_v[0] == 4) { 319 slen = ip->ip_len; 320 ip->ip_len = htons(fin->fin_hlen + sizeof(udp)); 321 swip = ip->ip_src; 322 sw2ip = ip->ip_dst; 323 ip->ip_src = nat->nat_ndstip; 324 ip->ip_dst = nat->nat_nsrcip; 325 } else { 326 #ifdef USE_INET6 327 slen = ip6->ip6_plen; 328 ip6->ip6_plen = htons(sizeof(udp)); 329 swip6.in6 = ip6->ip6_src; 330 sw2ip6.in6 = ip6->ip6_dst; 331 ip6->ip6_src = nat->nat_ndst6.in6; 332 ip6->ip6_dst = nat->nat_nsrc6.in6; 333 #endif 334 } 335 336 if (nat->nat_dir == NAT_INBOUND) { 337 dir = NAT_OUTBOUND; 338 fi.fin_out = 1; 339 } else { 340 dir = NAT_INBOUND; 341 fi.fin_out = 0; 342 } 343 nflags |= NAT_NOTRULEPORT; 344 345 MUTEX_ENTER(&softn->ipf_nat_new); 346 #ifdef USE_INET6 347 if (nat->nat_v[0] == 6) 348 nat2 = ipf_nat6_add(&fi, ti->ti_rule, NULL, nflags, dir); 349 else 350 #endif 351 nat2 = ipf_nat_add(&fi, ti->ti_rule, NULL, nflags, dir); 352 MUTEX_EXIT(&softn->ipf_nat_new); 353 if (nat2 != NULL) { 354 (void) ipf_nat_proto(&fi, nat2, IPN_UDP); 355 ipf_nat_update(&fi, nat2); 356 fi.fin_ifp = NULL; 357 if (ti->ti_rule->in_redir == NAT_MAP) { 358 fi.fin_src6 = nat->nat_ndst6; 359 fi.fin_dst6 = nat->nat_nsrc6; 360 if (nat->nat_v[0] == 4) { 361 ip->ip_src = nat->nat_ndstip; 362 ip->ip_dst = nat->nat_nsrcip; 363 } else { 364 #ifdef USE_INET6 365 ip6->ip6_src = nat->nat_ndst6.in6; 366 ip6->ip6_dst = nat->nat_nsrc6.in6; 367 #endif 368 } 369 } else { 370 fi.fin_src6 = nat->nat_odst6; 371 fi.fin_dst6 = nat->nat_osrc6; 372 if (fin->fin_v == 4) { 373 ip->ip_src = nat->nat_odstip; 374 ip->ip_dst = nat->nat_osrcip; 375 } else { 376 #ifdef USE_INET6 377 ip6->ip6_src = nat->nat_odst6.in6; 378 ip6->ip6_dst = nat->nat_osrc6.in6; 379 #endif 380 } 381 } 382 if (ipf_state_add(softc, &fi, NULL, SI_W_SPORT) != 0) { 383 ipf_nat_setpending(softc, nat2); 384 } 385 } 386 if (nat->nat_v[0] == 4) { 387 ip->ip_len = slen; 388 ip->ip_src = swip; 389 ip->ip_dst = sw2ip; 390 } else { 391 #ifdef USE_INET6 392 ip6->ip6_plen = slen; 393 ip6->ip6_src = swip6.in6; 394 ip6->ip6_dst = sw2ip6.in6; 395 #endif 396 } 397 return (0); 398 } 399 400 401 int 402 ipf_p_tftp_client(ipf_tftp_softc_t *softt, fr_info_t *fin, ap_session_t *aps, 403 nat_t *nat) 404 { 405 u_char *msg, *s, *t; 406 tftpinfo_t *ti; 407 u_short opcode; 408 udphdr_t *udp; 409 int len; 410 411 if (fin->fin_dlen < 4) 412 return (0); 413 414 ti = aps->aps_data; 415 msg = fin->fin_dp; 416 msg += sizeof(udphdr_t); 417 opcode = (msg[0] << 8) | msg[1]; 418 DT3(tftp_cmd, fr_info_t *, fin, int, opcode, nat_t *, nat); 419 420 switch (opcode) 421 { 422 case TFTP_CMD_WRITE : 423 if (softt->ipf_p_tftp_readonly != 0) 424 break; 425 /* FALLTHROUGH */ 426 case TFTP_CMD_READ : 427 len = fin->fin_dlen - sizeof(*udp) - 2; 428 if (len > sizeof(ti->ti_filename) - 1) 429 len = sizeof(ti->ti_filename) - 1; 430 s = msg + 2; 431 for (t = (u_char *)ti->ti_filename; (len > 0); len--, s++) { 432 *t++ = *s; 433 if (*s == '\0') 434 break; 435 } 436 ipf_p_tftp_backchannel(fin, aps, nat); 437 break; 438 default : 439 return (-1); 440 } 441 442 ti = aps->aps_data; 443 ti->ti_lastcmd = opcode; 444 return (0); 445 } 446 447 448 int 449 ipf_p_tftp_server(ipf_tftp_softc_t *softt, fr_info_t *fin, ap_session_t *aps, 450 nat_t *nat) 451 { 452 tftpinfo_t *ti; 453 u_short opcode; 454 u_short arg; 455 u_char *msg; 456 457 if (fin->fin_dlen < 4) 458 return (0); 459 460 ti = aps->aps_data; 461 msg = fin->fin_dp; 462 msg += sizeof(udphdr_t); 463 arg = (msg[2] << 8) | msg[3]; 464 opcode = (msg[0] << 8) | msg[1]; 465 466 switch (opcode) 467 { 468 case TFTP_CMD_ACK : 469 ti->ti_lastblk = arg; 470 break; 471 472 case TFTP_CMD_ERROR : 473 ti->ti_lasterror = arg; 474 break; 475 476 default : 477 return (-1); 478 } 479 480 ti->ti_lastcmd = opcode; 481 return (0); 482 } 483