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_rcmd_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 /*      $FreeBSD$       */
    2 
    3 /*
    4  * Copyright (C) 2012 by Darren Reed.
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  *
    8  * $Id$
    9  *
   10  * Simple RCMD transparent proxy for in-kernel use.  For use with the NAT
   11  * code.
   12  * $FreeBSD$
   13  */
   14 
   15 #define IPF_RCMD_PROXY
   16 
   17 typedef struct rcmdinfo {
   18         u_32_t  rcmd_port;      /* Port number seen */
   19         u_32_t  rcmd_portseq;   /* Sequence number where port is first seen */
   20         ipnat_t *rcmd_rule;     /* Template rule for back connection */
   21 } rcmdinfo_t;
   22 
   23 void ipf_p_rcmd_main_load(void);
   24 void ipf_p_rcmd_main_unload(void);
   25 
   26 int ipf_p_rcmd_init(void);
   27 void ipf_p_rcmd_fini(void);
   28 void ipf_p_rcmd_del(ipf_main_softc_t *, ap_session_t *);
   29 int ipf_p_rcmd_new(void *, fr_info_t *, ap_session_t *, nat_t *);
   30 int ipf_p_rcmd_out(void *, fr_info_t *, ap_session_t *, nat_t *);
   31 int ipf_p_rcmd_in(void *, fr_info_t *, ap_session_t *, nat_t *);
   32 u_short ipf_rcmd_atoi(char *);
   33 int ipf_p_rcmd_portmsg(fr_info_t *, ap_session_t *, nat_t *);
   34 
   35 static  frentry_t       rcmdfr;
   36 
   37 static  int             rcmd_proxy_init = 0;
   38 
   39 
   40 /*
   41  * RCMD application proxy initialization.
   42  */
   43 void
   44 ipf_p_rcmd_main_load(void)
   45 {
   46         bzero((char *)&rcmdfr, sizeof(rcmdfr));
   47         rcmdfr.fr_ref = 1;
   48         rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
   49         MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock");
   50         rcmd_proxy_init = 1;
   51 }
   52 
   53 
   54 void
   55 ipf_p_rcmd_main_unload(void)
   56 {
   57         if (rcmd_proxy_init == 1) {
   58                 MUTEX_DESTROY(&rcmdfr.fr_lock);
   59                 rcmd_proxy_init = 0;
   60         }
   61 }
   62 
   63 
   64 /*
   65  * Setup for a new RCMD proxy.
   66  */
   67 int
   68 ipf_p_rcmd_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
   69 {
   70         tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
   71         rcmdinfo_t *rc;
   72         ipnat_t *ipn;
   73         ipnat_t *np;
   74         int size;
   75 
   76         fin = fin;      /* LINT */
   77 
   78         np = nat->nat_ptr;
   79         size = np->in_size;
   80         KMALLOC(rc, rcmdinfo_t *);
   81         if (rc == NULL) {
   82 #ifdef IP_RCMD_PROXY_DEBUG
   83                 printf("ipf_p_rcmd_new:KMALLOCS(%d) failed\n", sizeof(*rc));
   84 #endif
   85                 return (-1);
   86         }
   87         aps->aps_sport = tcp->th_sport;
   88         aps->aps_dport = tcp->th_dport;
   89 
   90         ipn = ipf_proxy_rule_rev(nat);
   91         if (ipn == NULL) {
   92                 KFREE(rc);
   93                 return (-1);
   94         }
   95 
   96         aps->aps_data = rc;
   97         aps->aps_psiz = sizeof(*rc);
   98         bzero((char *)rc, sizeof(*rc));
   99 
  100         rc->rcmd_rule = ipn;
  101 
  102         return (0);
  103 }
  104 
  105 
  106 void
  107 ipf_p_rcmd_del(ipf_main_softc_t *softc, ap_session_t *aps)
  108 {
  109         rcmdinfo_t *rci;
  110 
  111         rci = aps->aps_data;
  112         if (rci != NULL) {
  113                 rci->rcmd_rule->in_flags |= IPN_DELETE;
  114                 ipf_nat_rule_deref(softc, &rci->rcmd_rule);
  115         }
  116 }
  117 
  118 
  119 /*
  120  * ipf_rcmd_atoi - implement a simple version of atoi
  121  */
  122 u_short
  123 ipf_rcmd_atoi(char *ptr)
  124 {
  125         register char *s = ptr, c;
  126         register u_short i = 0;
  127 
  128         while (((c = *s++) != '\0') && ISDIGIT(c)) {
  129                 i *= 10;
  130                 i += c - '';
  131         }
  132         return (i);
  133 }
  134 
  135 
  136 int
  137 ipf_p_rcmd_portmsg(fr_info_t *fin, ap_session_t *aps, nat_t *nat)
  138 {
  139         tcphdr_t *tcp, tcph, *tcp2 = &tcph;
  140         int off, dlen, nflags, direction;
  141         ipf_main_softc_t *softc;
  142         ipf_nat_softc_t *softn;
  143         char portbuf[8], *s;
  144         rcmdinfo_t *rc;
  145         fr_info_t fi;
  146         u_short sp;
  147         nat_t *nat2;
  148 #ifdef USE_INET6
  149         ip6_t *ip6;
  150 #endif
  151         int tcpsz;
  152         int slen = 0; /* silence gcc */
  153         ip_t *ip;
  154         mb_t *m;
  155 
  156         tcp = (tcphdr_t *)fin->fin_dp;
  157 
  158         m = fin->fin_m;
  159         ip = fin->fin_ip;
  160         tcpsz = TCP_OFF(tcp) << 2;
  161 #ifdef USE_INET6
  162         ip6 = (ip6_t *)fin->fin_ip;
  163 #endif
  164         softc = fin->fin_main_soft;
  165         softn = softc->ipf_nat_soft;
  166         off = (char *)tcp - (char *)ip + tcpsz + fin->fin_ipoff;
  167 
  168         dlen = fin->fin_dlen - tcpsz;
  169         if (dlen <= 0)
  170                 return (0);
  171 
  172         rc = (rcmdinfo_t *)aps->aps_data;
  173         if ((rc->rcmd_portseq != 0) &&
  174             (tcp->th_seq != rc->rcmd_portseq))
  175                 return (0);
  176 
  177         bzero(portbuf, sizeof(portbuf));
  178         COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf);
  179 
  180         portbuf[sizeof(portbuf) - 1] = '\0';
  181         s = portbuf;
  182         sp = ipf_rcmd_atoi(s);
  183         if (sp == 0) {
  184 #ifdef IP_RCMD_PROXY_DEBUG
  185                 printf("ipf_p_rcmd_portmsg:sp == 0 dlen %d [%s]\n",
  186                        dlen, portbuf);
  187 #endif
  188                 return (0);
  189         }
  190 
  191         if (rc->rcmd_port != 0 && sp != rc->rcmd_port) {
  192 #ifdef IP_RCMD_PROXY_DEBUG
  193                 printf("ipf_p_rcmd_portmsg:sp(%d) != rcmd_port(%d)\n",
  194                        sp, rc->rcmd_port);
  195 #endif
  196                 return (0);
  197         }
  198 
  199         rc->rcmd_port = sp;
  200         rc->rcmd_portseq = tcp->th_seq;
  201 
  202         /*
  203          * Initialise the packet info structure so we can search the NAT
  204          * table to see if there already is soemthing present that matches
  205          * up with what we want to add.
  206          */
  207         bcopy((char *)fin, (char *)&fi, sizeof(fi));
  208         fi.fin_flx |= FI_IGNORE;
  209         fi.fin_data[0] = 0;
  210         fi.fin_data[1] = sp;
  211         fi.fin_src6 = nat->nat_ndst6;
  212         fi.fin_dst6 = nat->nat_nsrc6;
  213 
  214         if (nat->nat_v[0] == 6) {
  215 #ifdef USE_INET6
  216                 if (nat->nat_dir == NAT_OUTBOUND) {
  217                         nat2 = ipf_nat6_outlookup(&fi, NAT_SEARCH|IPN_TCP,
  218                                                   nat->nat_pr[1],
  219                                                   &nat->nat_osrc6.in6,
  220                                                   &nat->nat_odst6.in6);
  221                 } else {
  222                         nat2 = ipf_nat6_inlookup(&fi, NAT_SEARCH|IPN_TCP,
  223                                                  nat->nat_pr[0],
  224                                                  &nat->nat_osrc6.in6,
  225                                                  &nat->nat_odst6.in6);
  226                 }
  227 #else
  228                 nat2 = (void *)-1;
  229 #endif
  230         } else {
  231                 if (nat->nat_dir == NAT_OUTBOUND) {
  232                         nat2 = ipf_nat_outlookup(&fi, NAT_SEARCH|IPN_TCP,
  233                                                  nat->nat_pr[1],
  234                                                  nat->nat_osrcip,
  235                                                  nat->nat_odstip);
  236                 } else {
  237                         nat2 = ipf_nat_inlookup(&fi, NAT_SEARCH|IPN_TCP,
  238                                                 nat->nat_pr[0],
  239                                                 nat->nat_osrcip,
  240                                                 nat->nat_odstip);
  241                 }
  242         }
  243         if (nat2 != NULL)
  244                 return (APR_ERR(1));
  245 
  246         /*
  247          * Add skeleton NAT entry for connection which will come
  248          * back the other way.
  249          */
  250 
  251         if (nat->nat_v[0] == 6) {
  252 #ifdef USE_INET6
  253                 slen = ip6->ip6_plen;
  254                 ip6->ip6_plen = htons(sizeof(*tcp));
  255 #endif
  256         } else {
  257                 slen = ip->ip_len;
  258                 ip->ip_len = htons(fin->fin_hlen + sizeof(*tcp));
  259         }
  260 
  261         /*
  262          * Fill out the fake TCP header with a few fields that ipfilter
  263          * considers to be important.
  264          */
  265         bzero((char *)tcp2, sizeof(*tcp2));
  266         tcp2->th_win = htons(8192);
  267         TCP_OFF_A(tcp2, 5);
  268         tcp2->th_flags = TH_SYN;
  269 
  270         fi.fin_dp = (char *)tcp2;
  271         fi.fin_fr = &rcmdfr;
  272         fi.fin_dlen = sizeof(*tcp2);
  273         fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
  274         fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
  275 
  276         if (nat->nat_dir == NAT_OUTBOUND) {
  277                 fi.fin_out = 0;
  278                 direction = NAT_INBOUND;
  279         } else {
  280                 fi.fin_out = 1;
  281                 direction = NAT_OUTBOUND;
  282         }
  283         nflags = SI_W_SPORT|NAT_SLAVE|IPN_TCP;
  284 
  285         MUTEX_ENTER(&softn->ipf_nat_new);
  286         if (fin->fin_v == 4)
  287                 nat2 = ipf_nat_add(&fi, rc->rcmd_rule, NULL, nflags,
  288                                    direction);
  289 #ifdef USE_INET6
  290         else
  291                 nat2 = ipf_nat6_add(&fi, rc->rcmd_rule, NULL, nflags,
  292                                     direction);
  293 #endif
  294         MUTEX_EXIT(&softn->ipf_nat_new);
  295 
  296         if (nat2 != NULL) {
  297                 (void) ipf_nat_proto(&fi, nat2, IPN_TCP);
  298                 MUTEX_ENTER(&nat2->nat_lock);
  299                 ipf_nat_update(&fi, nat2);
  300                 MUTEX_EXIT(&nat2->nat_lock);
  301                 fi.fin_ifp = NULL;
  302                 if (nat2->nat_dir == NAT_INBOUND)
  303                         fi.fin_dst6 = nat->nat_osrc6;
  304                 (void) ipf_state_add(softc, &fi, NULL, SI_W_SPORT);
  305         }
  306         if (nat->nat_v[0] == 6) {
  307 #ifdef USE_INET6
  308                 ip6->ip6_plen = slen;
  309 #endif
  310         } else {
  311                 ip->ip_len = slen;
  312         }
  313         if (nat2 == NULL)
  314                 return (APR_ERR(1));
  315         return (0);
  316 }
  317 
  318 
  319 int
  320 ipf_p_rcmd_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
  321 {
  322         if (nat->nat_dir == NAT_OUTBOUND)
  323                 return (ipf_p_rcmd_portmsg(fin, aps, nat));
  324         return (0);
  325 }
  326 
  327 
  328 int
  329 ipf_p_rcmd_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
  330 {
  331         if (nat->nat_dir == NAT_INBOUND)
  332                 return (ipf_p_rcmd_portmsg(fin, aps, nat));
  333         return (0);
  334 }

Cache object: c64ba0f15ce38df08711000e6928d62c


[ 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.