This is a discussion on Re: ipnat and tftp within the IPFilter forums, part of the System Security and Security Related category; This is a multi-part message in MIME format. --------------050609040704060709050506 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
This is a multi-part message in MIME format.
--------------050609040704060709050506 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Darren Reed wrote: > Hi, > > Since I saw your email, I sat down and worked on a TFTP proxy to fit > in with IPFilter. > > To make it work, you can take one of two paths. > 1) copy ip_tftp_pxy.c into the IPFilter source code tree, modify the > ip_proxy.c > file to include it and recompile IPFilter; > 2) if you're using 4.1.13 or later, you can compile it as a standalone > LKM and > load it into IPFilter for use that way. > > Darren > Sorry, forgot to attach the .c file. Darren --------------050609040704060709050506 Content-Type: text/plain; name="ip_tftp_pxy.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ip_tftp_pxy.c" /* * Copyright (C) 2006 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * */ #include <sys/types.h> #include <sys/modctl.h> #include <sys/ddi.h> #include <sys/uio.h> #include <sys/sunddi.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <netinet/tcp.h> #include <netinet/ip_compat.h> #include <netinet/ip_fil.h> #include <netinet/ip_nat.h> #include <netinet/ip_state.h> #include <netinet/ip_proxy.h> static int ipprtftpattach __P((dev_info_t *dip, ddi_attach_cmd_t cmd)); static int ipprtftpdetach __P((dev_info_t *dip, ddi_detach_cmd_t cmd)); static void ippr_tftp_fini __P((void)); static int ippr_tftp_new __P((fr_info_t *, ap_session_t *, nat_t *)); static int ippr_tftp_out __P((fr_info_t *, ap_session_t *, nat_t *)); static int ippr_tftp_in __P((fr_info_t *, ap_session_t *, nat_t *)); static int ippr_tftp_client __P((fr_info_t *, ap_session_t *, nat_t *)); static int ippr_tftp_server __P((fr_info_t *, ap_session_t *, nat_t *)); static int ippr_tftp_init __P((void)); static frentry_t tftpfr; static aproxy_t tftp_proxy = { NULL, "tftp", (char)IPPROTO_UDP, 0, 0, ippr_tftp_init, ippr_tftp_fini, ippr_tftp_new, NULL, /* del */ ippr_tftp_in, ippr_tftp_out, NULL, /* match */ NULL /* ctl */ }; int tftp_proxy_init = 0; typedef struct tftpinfo { nat_t *ti_datanat; ipstate_t *ti_datastate; int ti_lastcmd; int ti_nextblk; int ti_lastblk; int ti_lasterror; char ti_filename[80]; } tftpinfo_t; #define TFTP_CMD_READ 1 #define TFTP_CMD_WRITE 2 #define TFTP_CMD_DATA 3 #define TFTP_CMD_ACK 4 #define TFTP_CMD_ERROR 5 #ifdef STANDALONE static struct dev_ops drv_ops = { DEVO_REV, /* devo_rev */ 0, /* devo_refcnt */ nodev, /* devo_getinfo */ nulldev, /* devo_identify */ nulldev, /* devo_probe */ ipprtftpattach, /* devo_attach */ ipprtftpdetach, /* devo_detach */ nodev, /* devo_reset */ NULL, /* devo_cb_ops */ NULL, /* devo_bus_ops */ NULL, /* devo_power */ }; /* * Module linkage information for the kernel. */ static struct modldrv modldrv = { &mod_miscops, "IPFilter TFTP Proxy", &drv_ops /* driver ops */ }; static struct modlinkage modlinkage = { MODREV_1, &modldrv, NULL }; int _init() { if (mod_install(&modlinkage) != DDI_SUCCESS) { return DDI_FAILURE; } if (appr_add(&tftp_proxy) != 0) { printf("appr_add failed\n"); return DDI_FAILURE; } return DDI_SUCCESS; } int _fini() { if (appr_del(&tftp_proxy) != 0) { return DDI_FAILURE; } if (mod_remove(&modlinkage) != DDI_SUCCESS) return DDI_FAILURE; return DDI_SUCCESS; } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } static int ipprtftpattach(dip, cmd) dev_info_t *dip; ddi_attach_cmd_t cmd; { printf("ipprtftpattach(%p,%x)\n", dip, cmd); if (cmd != DDI_ATTACH) return DDI_FAILURE; if (appr_add(&tftp_proxy) != 0) return DDI_FAILURE; return DDI_SUCCESS; } static int ipprtftpdetach(dip, cmd) dev_info_t *dip; ddi_detach_cmd_t cmd; { if (cmd != DDI_DETACH) return DDI_FAILURE; if (appr_del(&tftp_proxy) != 0) return DDI_FAILURE; return DDI_SUCCESS; } #endif /* STANDALONE */ /* * RCMD application proxy initialization. */ int ippr_tftp_init() { bzero((char *)&tftpfr, sizeof(tftpfr)); tftpfr.fr_ref = 1; tftpfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; MUTEX_INIT(&tftpfr.fr_lock, "TFTP proxy rule lock"); tftp_proxy_init = 1; return 0; } void ippr_tftp_fini() { if (tftp_proxy_init == 1) { MUTEX_DESTROY(&tftpfr.fr_lock); tftp_proxy_init = 0; } } int ippr_tftp_out(fin, aps, nat) fr_info_t *fin; ap_session_t *aps; nat_t *nat; { if (nat->nat_dir == NAT_OUTBOUND) return ippr_tftp_client(fin, aps, nat); return ippr_tftp_server(fin, aps, nat); } int ippr_tftp_in(fin, aps, nat) fr_info_t *fin; ap_session_t *aps; nat_t *nat; { if (nat->nat_dir == NAT_INBOUND) return ippr_tftp_client(fin, aps, nat); return ippr_tftp_server(fin, aps, nat); } int ippr_tftp_new(fin, aps, nat) fr_info_t *fin; ap_session_t *aps; nat_t *nat; { udphdr_t *udp; tftpinfo_t *ti; KMALLOC(ti, tftpinfo_t *); if (ti == NULL) return -1; aps->aps_data = ti; aps->aps_psiz = sizeof(*ti); ti->ti_lastcmd = 0; nat = nat; /* LINT */ fin = fin; /* LINT */ udp = (udphdr_t *)fin->fin_dp; aps->aps_sport = udp->uh_sport; aps->aps_dport = udp->uh_dport; return 0; } /* * Setup for a new RCMD proxy. */ int ippr_tftp_backchannel(fin, aps, nat) fr_info_t *fin; ap_session_t *aps; nat_t *nat; { tftpinfo_t *ti; udphdr_t *udp; fr_info_t fi; u_short slen; nat_t *nat2; ti = aps->aps_data; udp = (udphdr_t *)fin->fin_dp; /* * Add skeleton NAT entry for connection which will come back the * other way. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); fi.fin_state = NULL; fi.fin_nat = NULL; fi.fin_flx |= FI_IGNORE; fi.fin_data[1] = 0; if (nat->nat_dir == NAT_OUTBOUND) nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_UDP, nat->nat_p, nat->nat_inip, nat->nat_oip); else nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_UDP, nat->nat_p, nat->nat_inip, nat->nat_oip); if (nat2 == NULL) { struct in_addr swip,swip2; int slen, nflags; ip_t *ip; ip = fin->fin_ip; slen = ip->ip_len; ip->ip_len = fin->fin_hlen + sizeof(*udp); bzero((char *)udp, sizeof(*udp)); udp->uh_sport = htons(fi.fin_data[0]); udp->uh_dport = 0; /* XXX - don't specify remote port */ udp->uh_ulen = 0; udp->uh_sum = 0; fi.fin_dp = (char *)udp; fi.fin_fr = &tftpfr; fi.fin_dlen = sizeof(*udp); fi.fin_plen = fi.fin_hlen + sizeof(*udp); fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; nflags = NAT_SLAVE|IPN_UDP|SI_W_DPORT; swip = ip->ip_src; swip2 = ip->ip_dst; if (nat->nat_dir == NAT_OUTBOUND) { fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; ip->ip_src = nat->nat_inip; } else { fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; ip->ip_src = nat->nat_oip; nflags |= NAT_NOTRULEPORT; } nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); if (nat2 != NULL) { (void) nat_proto(&fi, nat2, IPN_UDP); nat_update(&fi, nat2, nat2->nat_ptr); fi.fin_ifp = NULL; if (nat->nat_dir == NAT_INBOUND) { fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; ip->ip_dst = nat->nat_inip; } (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); if (fi.fin_state != NULL) fr_statederef(&fi, (ipstate_t **)&fi.fin_state); ti->ti_datanat = nat2; ti->ti_datastate = fi.fin_state; } ip->ip_src = swip; ip->ip_dst = swip2; return 0; } return -1; } int ippr_tftp_client(fin, aps, nat) fr_info_t *fin; ap_session_t *aps; nat_t *nat; { u_char *msg, *s, *t; tftpinfo_t *ti; u_short opcode; udphdr_t *udp; int len; if (fin->fin_dlen < 4) return 0; ti = aps->aps_data; msg = fin->fin_dp; msg += sizeof(udphdr_t); opcode = (msg[0] << 8) | msg[1]; switch (opcode) { case TFTP_CMD_READ : case TFTP_CMD_WRITE : if (fin->fin_out != 0) return -1; len = fin->fin_dlen - sizeof(*udp) - 2; if (len > sizeof(ti->ti_filename) - 1) len = sizeof(ti->ti_filename) - 1; s = msg + 2; for (t = (u_char *)ti->ti_filename; (len > 0); len--, s++) { *t++ = *s; if (*s == '\0') break; } break; default : return -1; } ti = aps->aps_data; ti->ti_lastcmd = opcode; return 0; } int ippr_tftp_server(fin, aps, nat) fr_info_t *fin; ap_session_t *aps; nat_t *nat; { tftpinfo_t *ti; u_short opcode; u_short arg; u_char *msg; if (fin->fin_dlen < 4) return 0; msg = fin->fin_dp; msg += sizeof(udphdr_t); opcode = (msg[0] << 8) | msg[1]; switch (opcode) { case TFTP_CMD_ACK : /* This proxy should not see any ACKS for DATA blocks */ if (fin->fin_out != 1) return -1; arg = (msg[2] << 8) | msg[3]; if ((arg == 0) && (ti->ti_lastcmd == TFTP_CMD_READ || ti->ti_lastcmd == TFTP_CMD_WRITE)) ippr_tftp_backchannel(fin, aps, nat); ti->ti_lastblk = arg; break; case TFTP_CMD_ERROR : if (fin->fin_out != 1) return -1; ti->ti_lasterror = arg; break; default : return -1; } ti = aps->aps_data; ti->ti_lastcmd = opcode; return 0; } --------------050609040704060709050506-- |