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