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/netgraph/ng_nat.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 2005, Gleb Smirnoff <glebius@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/kernel.h>
   32 #include <sys/mbuf.h>
   33 #include <sys/malloc.h>
   34 #include <sys/ctype.h>
   35 #include <sys/errno.h>
   36 #include <sys/syslog.h>
   37 
   38 #include <netinet/in_systm.h>
   39 #include <netinet/in.h>
   40 #include <netinet/ip.h>
   41 #include <netinet/ip_var.h>
   42 #include <netinet/tcp.h>
   43 #include <machine/in_cksum.h>
   44 
   45 #include <net/dlt.h>
   46 #include <net/ethernet.h>
   47 
   48 #include <netinet/libalias/alias.h>
   49 #include <netinet/libalias/alias_local.h>
   50 
   51 #include <netgraph/ng_message.h>
   52 #include <netgraph/ng_parse.h>
   53 #include <netgraph/ng_nat.h>
   54 #include <netgraph/netgraph.h>
   55 
   56 static ng_constructor_t ng_nat_constructor;
   57 static ng_rcvmsg_t      ng_nat_rcvmsg;
   58 static ng_shutdown_t    ng_nat_shutdown;
   59 static ng_newhook_t     ng_nat_newhook;
   60 static ng_rcvdata_t     ng_nat_rcvdata;
   61 static ng_disconnect_t  ng_nat_disconnect;
   62 
   63 static unsigned int     ng_nat_translate_flags(unsigned int x);
   64 
   65 /* Parse type for struct ng_nat_mode. */
   66 static const struct ng_parse_struct_field ng_nat_mode_fields[]
   67         = NG_NAT_MODE_INFO;
   68 static const struct ng_parse_type ng_nat_mode_type = {
   69         &ng_parse_struct_type,
   70         &ng_nat_mode_fields
   71 };
   72 
   73 /* Parse type for 'description' field in structs. */
   74 static const struct ng_parse_fixedstring_info ng_nat_description_info
   75         = { NG_NAT_DESC_LENGTH };
   76 static const struct ng_parse_type ng_nat_description_type = {
   77         &ng_parse_fixedstring_type,
   78         &ng_nat_description_info
   79 };
   80 
   81 /* Parse type for struct ng_nat_redirect_port. */
   82 static const struct ng_parse_struct_field ng_nat_redirect_port_fields[]
   83         = NG_NAT_REDIRECT_PORT_TYPE_INFO(&ng_nat_description_type);
   84 static const struct ng_parse_type ng_nat_redirect_port_type = {
   85         &ng_parse_struct_type,
   86         &ng_nat_redirect_port_fields
   87 };
   88 
   89 /* Parse type for struct ng_nat_redirect_addr. */
   90 static const struct ng_parse_struct_field ng_nat_redirect_addr_fields[]
   91         = NG_NAT_REDIRECT_ADDR_TYPE_INFO(&ng_nat_description_type);
   92 static const struct ng_parse_type ng_nat_redirect_addr_type = {
   93         &ng_parse_struct_type,
   94         &ng_nat_redirect_addr_fields
   95 };
   96 
   97 /* Parse type for struct ng_nat_redirect_proto. */
   98 static const struct ng_parse_struct_field ng_nat_redirect_proto_fields[]
   99         = NG_NAT_REDIRECT_PROTO_TYPE_INFO(&ng_nat_description_type);
  100 static const struct ng_parse_type ng_nat_redirect_proto_type = {
  101         &ng_parse_struct_type,
  102         &ng_nat_redirect_proto_fields
  103 };
  104 
  105 /* Parse type for struct ng_nat_add_server. */
  106 static const struct ng_parse_struct_field ng_nat_add_server_fields[]
  107         = NG_NAT_ADD_SERVER_TYPE_INFO;
  108 static const struct ng_parse_type ng_nat_add_server_type = {
  109         &ng_parse_struct_type,
  110         &ng_nat_add_server_fields
  111 };
  112 
  113 /* Parse type for one struct ng_nat_listrdrs_entry. */
  114 static const struct ng_parse_struct_field ng_nat_listrdrs_entry_fields[]
  115         = NG_NAT_LISTRDRS_ENTRY_TYPE_INFO(&ng_nat_description_type);
  116 static const struct ng_parse_type ng_nat_listrdrs_entry_type = {
  117         &ng_parse_struct_type,
  118         &ng_nat_listrdrs_entry_fields
  119 };
  120 
  121 /* Parse type for 'redirects' array in struct ng_nat_list_redirects. */
  122 static int
  123 ng_nat_listrdrs_ary_getLength(const struct ng_parse_type *type,
  124         const u_char *start, const u_char *buf)
  125 {
  126         const struct ng_nat_list_redirects *lr;
  127 
  128         lr = (const struct ng_nat_list_redirects *)
  129             (buf - offsetof(struct ng_nat_list_redirects, redirects));
  130         return lr->total_count;
  131 }
  132 
  133 static const struct ng_parse_array_info ng_nat_listrdrs_ary_info = {
  134         &ng_nat_listrdrs_entry_type,
  135         &ng_nat_listrdrs_ary_getLength,
  136         NULL
  137 };
  138 static const struct ng_parse_type ng_nat_listrdrs_ary_type = {
  139         &ng_parse_array_type,
  140         &ng_nat_listrdrs_ary_info
  141 };
  142 
  143 /* Parse type for struct ng_nat_list_redirects. */
  144 static const struct ng_parse_struct_field ng_nat_list_redirects_fields[]
  145         = NG_NAT_LIST_REDIRECTS_TYPE_INFO(&ng_nat_listrdrs_ary_type);
  146 static const struct ng_parse_type ng_nat_list_redirects_type = {
  147         &ng_parse_struct_type,
  148         &ng_nat_list_redirects_fields
  149 };
  150 
  151 /* Parse type for struct ng_nat_libalias_info. */
  152 static const struct ng_parse_struct_field ng_nat_libalias_info_fields[]
  153         = NG_NAT_LIBALIAS_INFO;
  154 static const struct ng_parse_type ng_nat_libalias_info_type = {
  155         &ng_parse_struct_type,
  156         &ng_nat_libalias_info_fields
  157 };
  158 
  159 /* List of commands and how to convert arguments to/from ASCII. */
  160 static const struct ng_cmdlist ng_nat_cmdlist[] = {
  161         {
  162           NGM_NAT_COOKIE,
  163           NGM_NAT_SET_IPADDR,
  164           "setaliasaddr",
  165           &ng_parse_ipaddr_type,
  166           NULL
  167         },
  168         {
  169           NGM_NAT_COOKIE,
  170           NGM_NAT_SET_MODE,
  171           "setmode",
  172           &ng_nat_mode_type,
  173           NULL
  174         },
  175         {
  176           NGM_NAT_COOKIE,
  177           NGM_NAT_SET_TARGET,
  178           "settarget",
  179           &ng_parse_ipaddr_type,
  180           NULL
  181         },
  182         {
  183           NGM_NAT_COOKIE,
  184           NGM_NAT_REDIRECT_PORT,
  185           "redirectport",
  186           &ng_nat_redirect_port_type,
  187           &ng_parse_uint32_type
  188         },
  189         {
  190           NGM_NAT_COOKIE,
  191           NGM_NAT_REDIRECT_ADDR,
  192           "redirectaddr",
  193           &ng_nat_redirect_addr_type,
  194           &ng_parse_uint32_type
  195         },
  196         {
  197           NGM_NAT_COOKIE,
  198           NGM_NAT_REDIRECT_PROTO,
  199           "redirectproto",
  200           &ng_nat_redirect_proto_type,
  201           &ng_parse_uint32_type
  202         },
  203         {
  204           NGM_NAT_COOKIE,
  205           NGM_NAT_REDIRECT_DYNAMIC,
  206           "redirectdynamic",
  207           &ng_parse_uint32_type,
  208           NULL
  209         },
  210         {
  211           NGM_NAT_COOKIE,
  212           NGM_NAT_REDIRECT_DELETE,
  213           "redirectdelete",
  214           &ng_parse_uint32_type,
  215           NULL
  216         },
  217         {
  218           NGM_NAT_COOKIE,
  219           NGM_NAT_ADD_SERVER,
  220           "addserver",
  221           &ng_nat_add_server_type,
  222           NULL
  223         },
  224         {
  225           NGM_NAT_COOKIE,
  226           NGM_NAT_LIST_REDIRECTS,
  227           "listredirects",
  228           NULL,
  229           &ng_nat_list_redirects_type
  230         },
  231         {
  232           NGM_NAT_COOKIE,
  233           NGM_NAT_PROXY_RULE,
  234           "proxyrule",
  235           &ng_parse_string_type,
  236           NULL
  237         },
  238         {
  239           NGM_NAT_COOKIE,
  240           NGM_NAT_LIBALIAS_INFO,
  241           "libaliasinfo",
  242           NULL,
  243           &ng_nat_libalias_info_type
  244         },
  245         {
  246           NGM_NAT_COOKIE,
  247           NGM_NAT_SET_DLT,
  248           "setdlt",
  249           &ng_parse_uint8_type,
  250           NULL
  251         },
  252         {
  253           NGM_NAT_COOKIE,
  254           NGM_NAT_GET_DLT,
  255           "getdlt",
  256           NULL,
  257           &ng_parse_uint8_type
  258         },
  259         { 0 }
  260 };
  261 
  262 /* Netgraph node type descriptor. */
  263 static struct ng_type typestruct = {
  264         .version =      NG_ABI_VERSION,
  265         .name =         NG_NAT_NODE_TYPE,
  266         .constructor =  ng_nat_constructor,
  267         .rcvmsg =       ng_nat_rcvmsg,
  268         .shutdown =     ng_nat_shutdown,
  269         .newhook =      ng_nat_newhook,
  270         .rcvdata =      ng_nat_rcvdata,
  271         .disconnect =   ng_nat_disconnect,
  272         .cmdlist =      ng_nat_cmdlist,
  273 };
  274 NETGRAPH_INIT(nat, &typestruct);
  275 MODULE_DEPEND(ng_nat, libalias, 1, 1, 1);
  276 
  277 /* Element for list of redirects. */
  278 struct ng_nat_rdr_lst {
  279         STAILQ_ENTRY(ng_nat_rdr_lst) entries;
  280         struct alias_link       *lnk;
  281         struct ng_nat_listrdrs_entry rdr;
  282 };
  283 STAILQ_HEAD(rdrhead, ng_nat_rdr_lst);
  284 
  285 /* Information we store for each node. */
  286 struct ng_nat_priv {
  287         node_p          node;           /* back pointer to node */
  288         hook_p          in;             /* hook for demasquerading */
  289         hook_p          out;            /* hook for masquerading */
  290         struct libalias *lib;           /* libalias handler */
  291         uint32_t        flags;          /* status flags */
  292         uint32_t        rdrcount;       /* number or redirects in list */
  293         uint32_t        nextid;         /* for next in turn in list */
  294         struct rdrhead  redirhead;      /* redirect list header */
  295         uint8_t         dlt;            /* DLT_XXX from bpf.h */
  296 };
  297 typedef struct ng_nat_priv *priv_p;
  298 
  299 /* Values of flags */
  300 #define NGNAT_CONNECTED         0x1     /* We have both hooks connected */
  301 #define NGNAT_ADDR_DEFINED      0x2     /* NGM_NAT_SET_IPADDR happened */
  302 
  303 static int
  304 ng_nat_constructor(node_p node)
  305 {
  306         priv_p priv;
  307 
  308         /* Initialize private descriptor. */
  309         priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
  310 
  311         /* Init aliasing engine. */
  312         priv->lib = LibAliasInit(NULL);
  313 
  314         /* Set same ports on. */
  315         (void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS,
  316             PKT_ALIAS_SAME_PORTS);
  317 
  318         /* Init redirects housekeeping. */
  319         priv->rdrcount = 0;
  320         priv->nextid = 1;
  321         priv->dlt = DLT_RAW;
  322         STAILQ_INIT(&priv->redirhead);
  323 
  324         /* Link structs together. */
  325         NG_NODE_SET_PRIVATE(node, priv);
  326         priv->node = node;
  327 
  328         /*
  329          * libalias is not thread safe, so our node
  330          * must be single threaded.
  331          */
  332         NG_NODE_FORCE_WRITER(node);
  333 
  334         return (0);
  335 }
  336 
  337 static int
  338 ng_nat_newhook(node_p node, hook_p hook, const char *name)
  339 {
  340         const priv_p priv = NG_NODE_PRIVATE(node);
  341 
  342         if (strcmp(name, NG_NAT_HOOK_IN) == 0) {
  343                 priv->in = hook;
  344         } else if (strcmp(name, NG_NAT_HOOK_OUT) == 0) {
  345                 priv->out = hook;
  346         } else
  347                 return (EINVAL);
  348 
  349         if (priv->out != NULL &&
  350             priv->in != NULL)
  351                 priv->flags |= NGNAT_CONNECTED;
  352 
  353         return(0);
  354 }
  355 
  356 static int
  357 ng_nat_rcvmsg(node_p node, item_p item, hook_p lasthook)
  358 {
  359         const priv_p priv = NG_NODE_PRIVATE(node);
  360         struct ng_mesg *resp = NULL;
  361         struct ng_mesg *msg;
  362         int error = 0;
  363 
  364         NGI_GET_MSG(item, msg);
  365 
  366         switch (msg->header.typecookie) {
  367         case NGM_NAT_COOKIE:
  368                 switch (msg->header.cmd) {
  369                 case NGM_NAT_SET_IPADDR:
  370                     {
  371                         struct in_addr *const ia = (struct in_addr *)msg->data;
  372 
  373                         if (msg->header.arglen < sizeof(*ia)) {
  374                                 error = EINVAL;
  375                                 break;
  376                         }
  377 
  378                         LibAliasSetAddress(priv->lib, *ia);
  379 
  380                         priv->flags |= NGNAT_ADDR_DEFINED;
  381                     }
  382                         break;
  383                 case NGM_NAT_SET_MODE:
  384                     {
  385                         struct ng_nat_mode *const mode = 
  386                             (struct ng_nat_mode *)msg->data;
  387 
  388                         if (msg->header.arglen < sizeof(*mode)) {
  389                                 error = EINVAL;
  390                                 break;
  391                         }
  392                         
  393                         if (LibAliasSetMode(priv->lib, 
  394                             ng_nat_translate_flags(mode->flags),
  395                             ng_nat_translate_flags(mode->mask)) < 0) {
  396                                 error = ENOMEM;
  397                                 break;
  398                         }
  399                     }
  400                         break;
  401                 case NGM_NAT_SET_TARGET:
  402                     {
  403                         struct in_addr *const ia = (struct in_addr *)msg->data;
  404 
  405                         if (msg->header.arglen < sizeof(*ia)) {
  406                                 error = EINVAL;
  407                                 break;
  408                         }
  409 
  410                         LibAliasSetTarget(priv->lib, *ia);
  411                     }
  412                         break;
  413                 case NGM_NAT_REDIRECT_PORT:
  414                     {
  415                         struct ng_nat_rdr_lst *entry;
  416                         struct ng_nat_redirect_port *const rp =
  417                             (struct ng_nat_redirect_port *)msg->data;
  418 
  419                         if (msg->header.arglen < sizeof(*rp)) {
  420                                 error = EINVAL;
  421                                 break;
  422                         }
  423 
  424                         if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
  425                             M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
  426                                 error = ENOMEM;
  427                                 break;
  428                         }
  429 
  430                         /* Try actual redirect. */
  431                         entry->lnk = LibAliasRedirectPort(priv->lib,
  432                                 rp->local_addr, htons(rp->local_port),
  433                                 rp->remote_addr, htons(rp->remote_port),
  434                                 rp->alias_addr, htons(rp->alias_port),
  435                                 rp->proto);
  436 
  437                         if (entry->lnk == NULL) {
  438                                 error = ENOMEM;
  439                                 free(entry, M_NETGRAPH);
  440                                 break;
  441                         }
  442 
  443                         /* Successful, save info in our internal list. */
  444                         entry->rdr.local_addr = rp->local_addr;
  445                         entry->rdr.alias_addr = rp->alias_addr;
  446                         entry->rdr.remote_addr = rp->remote_addr;
  447                         entry->rdr.local_port = rp->local_port;
  448                         entry->rdr.alias_port = rp->alias_port;
  449                         entry->rdr.remote_port = rp->remote_port;
  450                         entry->rdr.proto = rp->proto;
  451                         bcopy(rp->description, entry->rdr.description,
  452                             NG_NAT_DESC_LENGTH);
  453 
  454                         /* Safety precaution. */
  455                         entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
  456 
  457                         entry->rdr.id = priv->nextid++;
  458                         priv->rdrcount++;
  459 
  460                         /* Link to list of redirects. */
  461                         STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
  462 
  463                         /* Response with id of newly added entry. */
  464                         NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
  465                         if (resp == NULL) {
  466                                 error = ENOMEM;
  467                                 break;
  468                         }
  469                         bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
  470                     }
  471                         break;
  472                 case NGM_NAT_REDIRECT_ADDR:
  473                     {
  474                         struct ng_nat_rdr_lst *entry;
  475                         struct ng_nat_redirect_addr *const ra =
  476                             (struct ng_nat_redirect_addr *)msg->data;
  477 
  478                         if (msg->header.arglen < sizeof(*ra)) {
  479                                 error = EINVAL;
  480                                 break;
  481                         }
  482 
  483                         if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
  484                             M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
  485                                 error = ENOMEM;
  486                                 break;
  487                         }
  488 
  489                         /* Try actual redirect. */
  490                         entry->lnk = LibAliasRedirectAddr(priv->lib,
  491                                 ra->local_addr, ra->alias_addr);
  492 
  493                         if (entry->lnk == NULL) {
  494                                 error = ENOMEM;
  495                                 free(entry, M_NETGRAPH);
  496                                 break;
  497                         }
  498 
  499                         /* Successful, save info in our internal list. */
  500                         entry->rdr.local_addr = ra->local_addr;
  501                         entry->rdr.alias_addr = ra->alias_addr;
  502                         entry->rdr.proto = NG_NAT_REDIRPROTO_ADDR;
  503                         bcopy(ra->description, entry->rdr.description,
  504                             NG_NAT_DESC_LENGTH);
  505 
  506                         /* Safety precaution. */
  507                         entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
  508 
  509                         entry->rdr.id = priv->nextid++;
  510                         priv->rdrcount++;
  511 
  512                         /* Link to list of redirects. */
  513                         STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
  514 
  515                         /* Response with id of newly added entry. */
  516                         NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
  517                         if (resp == NULL) {
  518                                 error = ENOMEM;
  519                                 break;
  520                         }
  521                         bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
  522                     }
  523                         break;
  524                 case NGM_NAT_REDIRECT_PROTO:
  525                     {
  526                         struct ng_nat_rdr_lst *entry;
  527                         struct ng_nat_redirect_proto *const rp =
  528                             (struct ng_nat_redirect_proto *)msg->data;
  529 
  530                         if (msg->header.arglen < sizeof(*rp)) {
  531                                 error = EINVAL;
  532                                 break;
  533                         }
  534 
  535                         if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
  536                             M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
  537                                 error = ENOMEM;
  538                                 break;
  539                         }
  540 
  541                         /* Try actual redirect. */
  542                         entry->lnk = LibAliasRedirectProto(priv->lib,
  543                                 rp->local_addr, rp->remote_addr,
  544                                 rp->alias_addr, rp->proto);
  545 
  546                         if (entry->lnk == NULL) {
  547                                 error = ENOMEM;
  548                                 free(entry, M_NETGRAPH);
  549                                 break;
  550                         }
  551 
  552                         /* Successful, save info in our internal list. */
  553                         entry->rdr.local_addr = rp->local_addr;
  554                         entry->rdr.alias_addr = rp->alias_addr;
  555                         entry->rdr.remote_addr = rp->remote_addr;
  556                         entry->rdr.proto = rp->proto;
  557                         bcopy(rp->description, entry->rdr.description,
  558                             NG_NAT_DESC_LENGTH);
  559 
  560                         /* Safety precaution. */
  561                         entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
  562 
  563                         entry->rdr.id = priv->nextid++;
  564                         priv->rdrcount++;
  565 
  566                         /* Link to list of redirects. */
  567                         STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
  568 
  569                         /* Response with id of newly added entry. */
  570                         NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
  571                         if (resp == NULL) {
  572                                 error = ENOMEM;
  573                                 break;
  574                         }
  575                         bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
  576                     }
  577                         break;
  578                 case NGM_NAT_REDIRECT_DYNAMIC:
  579                 case NGM_NAT_REDIRECT_DELETE:
  580                     {
  581                         struct ng_nat_rdr_lst *entry;
  582                         uint32_t *const id = (uint32_t *)msg->data;
  583 
  584                         if (msg->header.arglen < sizeof(*id)) {
  585                                 error = EINVAL;
  586                                 break;
  587                         }
  588 
  589                         /* Find entry with supplied id. */
  590                         STAILQ_FOREACH(entry, &priv->redirhead, entries) {
  591                                 if (entry->rdr.id == *id)
  592                                         break;
  593                         }
  594 
  595                         /* Not found. */
  596                         if (entry == NULL) {
  597                                 error = ENOENT;
  598                                 break;
  599                         }
  600 
  601                         if (msg->header.cmd == NGM_NAT_REDIRECT_DYNAMIC) {
  602                                 if (LibAliasRedirectDynamic(priv->lib,
  603                                     entry->lnk) == -1) {
  604                                         error = ENOTTY; /* XXX Something better? */
  605                                         break;
  606                                 }
  607                         } else {        /* NGM_NAT_REDIRECT_DELETE */
  608                                 LibAliasRedirectDelete(priv->lib, entry->lnk);
  609                         }
  610 
  611                         /* Delete entry from our internal list. */
  612                         priv->rdrcount--;
  613                         STAILQ_REMOVE(&priv->redirhead, entry, ng_nat_rdr_lst, entries);
  614                         free(entry, M_NETGRAPH);
  615                     }
  616                         break;
  617                 case NGM_NAT_ADD_SERVER:
  618                     {
  619                         struct ng_nat_rdr_lst *entry;
  620                         struct ng_nat_add_server *const as =
  621                             (struct ng_nat_add_server *)msg->data;
  622 
  623                         if (msg->header.arglen < sizeof(*as)) {
  624                                 error = EINVAL;
  625                                 break;
  626                         }
  627 
  628                         /* Find entry with supplied id. */
  629                         STAILQ_FOREACH(entry, &priv->redirhead, entries) {
  630                                 if (entry->rdr.id == as->id)
  631                                         break;
  632                         }
  633 
  634                         /* Not found. */
  635                         if (entry == NULL) {
  636                                 error = ENOENT;
  637                                 break;
  638                         }
  639 
  640                         if (LibAliasAddServer(priv->lib, entry->lnk,
  641                             as->addr, htons(as->port)) == -1) {
  642                                 error = ENOMEM;
  643                                 break;
  644                         }
  645 
  646                         entry->rdr.lsnat++;
  647                     }
  648                         break;
  649                 case NGM_NAT_LIST_REDIRECTS:
  650                     {
  651                         struct ng_nat_rdr_lst *entry;
  652                         struct ng_nat_list_redirects *ary; 
  653                         int i = 0;
  654 
  655                         NG_MKRESPONSE(resp, msg, sizeof(*ary) +
  656                             (priv->rdrcount) * sizeof(*entry), M_NOWAIT);
  657                         if (resp == NULL) {
  658                                 error = ENOMEM;
  659                                 break;
  660                         }
  661 
  662                         ary = (struct ng_nat_list_redirects *)resp->data;
  663                         ary->total_count = priv->rdrcount;
  664 
  665                         STAILQ_FOREACH(entry, &priv->redirhead, entries) {
  666                                 bcopy(&entry->rdr, &ary->redirects[i++],
  667                                     sizeof(struct ng_nat_listrdrs_entry));
  668                         }
  669                     }
  670                         break;
  671                 case NGM_NAT_PROXY_RULE:
  672                     {
  673                         char *cmd = (char *)msg->data;
  674 
  675                         if (msg->header.arglen < 6) {
  676                                 error = EINVAL;
  677                                 break;
  678                         }
  679 
  680                         if (LibAliasProxyRule(priv->lib, cmd) != 0)
  681                                 error = ENOMEM;
  682                     }
  683                         break;
  684                 case NGM_NAT_LIBALIAS_INFO:
  685                     {
  686                         struct ng_nat_libalias_info *i;
  687 
  688                         NG_MKRESPONSE(resp, msg,
  689                             sizeof(struct ng_nat_libalias_info), M_NOWAIT);
  690                         if (resp == NULL) {
  691                                 error = ENOMEM;
  692                                 break;
  693                         }
  694                         i = (struct ng_nat_libalias_info *)resp->data;
  695 #define COPY(F) do {                                            \
  696         if (priv->lib->F >= 0 && priv->lib->F < UINT32_MAX)     \
  697                 i->F = priv->lib->F;                            \
  698         else                                                    \
  699                 i->F = UINT32_MAX;                              \
  700 } while (0)
  701                 
  702                         COPY(icmpLinkCount);
  703                         COPY(udpLinkCount);
  704                         COPY(tcpLinkCount);
  705                         COPY(pptpLinkCount);
  706                         COPY(sctpLinkCount);
  707                         COPY(protoLinkCount);
  708                         COPY(fragmentIdLinkCount);
  709                         COPY(fragmentPtrLinkCount);
  710                         COPY(sockCount);
  711 #undef COPY
  712                     }
  713                         break;
  714                 case NGM_NAT_SET_DLT:
  715                         if (msg->header.arglen != sizeof(uint8_t)) {
  716                                 error = EINVAL;
  717                                 break;
  718                         }
  719                         switch (*(uint8_t *) msg->data) {
  720                         case DLT_EN10MB:
  721                         case DLT_RAW:
  722                                 priv->dlt = *(uint8_t *) msg->data;
  723                                 break;
  724                         default:
  725                                 error = EINVAL;
  726                                 break;
  727                         }
  728                         break;
  729                 default:
  730                         error = EINVAL;         /* unknown command */
  731                         break;
  732                 }
  733                 break;
  734                 case NGM_NAT_GET_DLT:
  735                         NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
  736                         if (resp == NULL) {
  737                                 error = ENOMEM;
  738                                 break;
  739                         }
  740                         *((uint8_t *) resp->data) = priv->dlt;
  741                         break;
  742         default:
  743                 error = EINVAL;                 /* unknown cookie type */
  744                 break;
  745         }
  746 
  747         NG_RESPOND_MSG(error, node, item, resp);
  748         NG_FREE_MSG(msg);
  749         return (error);
  750 }
  751 
  752 static int
  753 ng_nat_rcvdata(hook_p hook, item_p item )
  754 {
  755         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  756         struct mbuf     *m;
  757         struct ip       *ip;
  758         int rval, ipofs, error = 0;
  759         char *c;
  760 
  761         /* We have no required hooks. */
  762         if (!(priv->flags & NGNAT_CONNECTED)) {
  763                 NG_FREE_ITEM(item);
  764                 return (ENXIO);
  765         }
  766 
  767         /* We have no alias address yet to do anything. */
  768         if (!(priv->flags & NGNAT_ADDR_DEFINED))
  769                 goto send;
  770 
  771         m = NGI_M(item);
  772 
  773         if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) {
  774                 NGI_M(item) = NULL;     /* avoid double free */
  775                 NG_FREE_ITEM(item);
  776                 return (ENOBUFS);
  777         }
  778 
  779         NGI_M(item) = m;
  780 
  781         switch (priv->dlt) {
  782         case DLT_RAW:
  783                 ipofs = 0;
  784                 break;
  785         case DLT_EN10MB:
  786             {
  787                 struct ether_header *eh;
  788 
  789                 if (m->m_pkthdr.len < sizeof(struct ether_header)) {
  790                         NG_FREE_ITEM(item);
  791                         return (ENXIO);
  792                 }
  793                 eh = mtod(m, struct ether_header *);
  794                 switch (ntohs(eh->ether_type)) {
  795                 case ETHERTYPE_IP:
  796                         ipofs = sizeof(struct ether_header);
  797                         break;
  798                 default:
  799                         goto send;
  800                 }
  801                 break;
  802             }
  803         default:
  804                 panic("Corrupted priv->dlt: %u", priv->dlt);
  805         }
  806 
  807         if (m->m_pkthdr.len < ipofs + sizeof(struct ip))
  808                 goto send;              /* packet too short to hold IP */
  809 
  810         c = (char *)mtodo(m, ipofs);
  811         ip = (struct ip *)mtodo(m, ipofs);
  812 
  813         if (ip->ip_v != IPVERSION)
  814                 goto send;              /* other IP version, let it pass */
  815         if (m->m_pkthdr.len < ipofs + ntohs(ip->ip_len))
  816                 goto send;              /* packet too short (i.e. fragmented or broken) */
  817 
  818         /*
  819          * We drop packet when:
  820          * 1. libalias returns PKT_ALIAS_ERROR;
  821          * 2. For incoming packets:
  822          *      a) for unresolved fragments;
  823          *      b) libalias returns PKT_ALIAS_IGNORED and
  824          *              PKT_ALIAS_DENY_INCOMING flag is set.
  825          */
  826         if (hook == priv->in) {
  827                 rval = LibAliasIn(priv->lib, c, m->m_len - ipofs +
  828                     M_TRAILINGSPACE(m));
  829                 if (rval == PKT_ALIAS_ERROR ||
  830                     rval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
  831                     (rval == PKT_ALIAS_IGNORED &&
  832                      (priv->lib->packetAliasMode &
  833                       PKT_ALIAS_DENY_INCOMING) != 0)) {
  834                         NG_FREE_ITEM(item);
  835                         return (EINVAL);
  836                 }
  837         } else if (hook == priv->out) {
  838                 rval = LibAliasOut(priv->lib, c, m->m_len - ipofs +
  839                     M_TRAILINGSPACE(m));
  840                 if (rval == PKT_ALIAS_ERROR) {
  841                         NG_FREE_ITEM(item);
  842                         return (EINVAL);
  843                 }
  844         } else
  845                 panic("ng_nat: unknown hook!\n");
  846 
  847         if (rval == PKT_ALIAS_RESPOND)
  848                 m->m_flags |= M_SKIP_FIREWALL;
  849         m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len) + ipofs;
  850 
  851         if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
  852             ip->ip_p == IPPROTO_TCP) {
  853                 struct tcphdr *th = (struct tcphdr *)((caddr_t)ip +
  854                     (ip->ip_hl << 2));
  855 
  856                 /*
  857                  * Here is our terrible HACK.
  858                  *
  859                  * Sometimes LibAlias edits contents of TCP packet.
  860                  * In this case it needs to recompute full TCP
  861                  * checksum. However, the problem is that LibAlias
  862                  * doesn't have any idea about checksum offloading
  863                  * in kernel. To workaround this, we do not do
  864                  * checksumming in LibAlias, but only mark the
  865                  * packets in th_x2 field. If we receive a marked
  866                  * packet, we calculate correct checksum for it
  867                  * aware of offloading.
  868                  *
  869                  * Why do I do such a terrible hack instead of
  870                  * recalculating checksum for each packet?
  871                  * Because the previous checksum was not checked!
  872                  * Recalculating checksums for EVERY packet will
  873                  * hide ALL transmission errors. Yes, marked packets
  874                  * still suffer from this problem. But, sigh, natd(8)
  875                  * has this problem, too.
  876                  */
  877 
  878                 if (th->th_x2) {
  879                         uint16_t ip_len = ntohs(ip->ip_len);
  880 
  881                         th->th_x2 = 0;
  882                         th->th_sum = in_pseudo(ip->ip_src.s_addr,
  883                             ip->ip_dst.s_addr, htons(IPPROTO_TCP +
  884                             ip_len - (ip->ip_hl << 2)));
  885         
  886                         if ((m->m_pkthdr.csum_flags & CSUM_TCP) == 0) {
  887                                 m->m_pkthdr.csum_data = offsetof(struct tcphdr,
  888                                     th_sum);
  889                                 in_delayed_cksum(m);
  890                         }
  891                 }
  892         }
  893 
  894 send:
  895         if (hook == priv->in)
  896                 NG_FWD_ITEM_HOOK(error, item, priv->out);
  897         else
  898                 NG_FWD_ITEM_HOOK(error, item, priv->in);
  899 
  900         return (error);
  901 }
  902 
  903 static int
  904 ng_nat_shutdown(node_p node)
  905 {
  906         const priv_p priv = NG_NODE_PRIVATE(node);
  907 
  908         NG_NODE_SET_PRIVATE(node, NULL);
  909         NG_NODE_UNREF(node);
  910 
  911         /* Free redirects list. */
  912         while (!STAILQ_EMPTY(&priv->redirhead)) {
  913                 struct ng_nat_rdr_lst *entry = STAILQ_FIRST(&priv->redirhead);
  914                 STAILQ_REMOVE_HEAD(&priv->redirhead, entries);
  915                 free(entry, M_NETGRAPH);
  916         }
  917 
  918         /* Final free. */
  919         LibAliasUninit(priv->lib);
  920         free(priv, M_NETGRAPH);
  921 
  922         return (0);
  923 }
  924 
  925 static int
  926 ng_nat_disconnect(hook_p hook)
  927 {
  928         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  929 
  930         priv->flags &= ~NGNAT_CONNECTED;
  931 
  932         if (hook == priv->out)
  933                 priv->out = NULL;
  934         if (hook == priv->in)
  935                 priv->in = NULL;
  936 
  937         if (priv->out == NULL && priv->in == NULL)
  938                 ng_rmnode_self(NG_HOOK_NODE(hook));
  939 
  940         return (0);
  941 }
  942 
  943 static unsigned int
  944 ng_nat_translate_flags(unsigned int x)
  945 {
  946         unsigned int    res = 0;
  947         
  948         if (x & NG_NAT_LOG)
  949                 res |= PKT_ALIAS_LOG;
  950         if (x & NG_NAT_DENY_INCOMING)
  951                 res |= PKT_ALIAS_DENY_INCOMING;
  952         if (x & NG_NAT_SAME_PORTS)
  953                 res |= PKT_ALIAS_SAME_PORTS;
  954         if (x & NG_NAT_UNREGISTERED_ONLY)
  955                 res |= PKT_ALIAS_UNREGISTERED_ONLY;
  956         if (x & NG_NAT_RESET_ON_ADDR_CHANGE)
  957                 res |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
  958         if (x & NG_NAT_PROXY_ONLY)
  959                 res |= PKT_ALIAS_PROXY_ONLY;
  960         if (x & NG_NAT_REVERSE)
  961                 res |= PKT_ALIAS_REVERSE;
  962         if (x & NG_NAT_UNREGISTERED_CGN)
  963                 res |= PKT_ALIAS_UNREGISTERED_CGN;
  964 
  965         return (res);
  966 }

Cache object: 9323f3342e85265b8aa410cecb7e745f


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