The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: f9f6e545a4b78842be0549ed7c754105


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.