Annotation of embedaddon/mpd/src/ngfunc.c, revision 1.1.1.3

1.1       misho       1: 
                      2: /*
                      3:  * ngfunc.c
                      4:  *
                      5:  * Written by Archie Cobbs <archie@freebsd.org>
                      6:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
                      7:  * See ``COPYRIGHT.whistle''
                      8:  *
                      9:  * TCP MSSFIX contributed by Sergey Korolew <dsATbittu.org.ru>
                     10:  *
                     11:  * Routines for doing netgraph stuff
                     12:  *
                     13:  */
                     14: 
                     15: #include "defs.h"
                     16: #include "ppp.h"
                     17: #include "bund.h"
                     18: #include "ngfunc.h"
                     19: #include "input.h"
                     20: #include "ccp.h"
                     21: #include "netgraph.h"
                     22: #include "command.h"
                     23: #include "util.h"
                     24: 
                     25: #ifdef USE_NG_BPF
                     26: #include <net/bpf.h>
                     27: #endif
                     28: #include <arpa/inet.h>
                     29: 
                     30: #include <netgraph/ng_message.h>
                     31: 
                     32: #include <netgraph/ng_socket.h>
                     33: #include <netgraph/ng_ksocket.h>
                     34: #include <netgraph/ng_iface.h>
                     35: #ifdef USE_NG_VJC
                     36: #include <netgraph/ng_vjc.h>
                     37: #endif
                     38: #ifdef USE_NG_BPF
                     39: #include <netgraph/ng_bpf.h>
                     40: #endif
                     41: #include <netgraph/ng_tee.h>
                     42: #ifdef USE_NG_TCPMSS
                     43: #include <netgraph/ng_tcpmss.h>
                     44: #endif
                     45: #ifdef USE_NG_NETFLOW
                     46: #include <netgraph/netflow/ng_netflow.h>
                     47: #include <netgraph/netflow/netflow.h>
1.1.1.2   misho      48: #if NGM_NETFLOW_COOKIE >= 1309868867
1.1       misho      49: #include <netgraph/netflow/netflow_v9.h>
                     50: #endif
                     51: #endif
                     52: #ifdef USE_NG_PRED1
                     53: #include <netgraph/ng_pred1.h>
                     54: #endif
                     55: 
                     56: #include <netinet/ip_icmp.h>
                     57: #include <netinet/tcp.h>
                     58: 
                     59: /*
                     60:  * DEFINITIONS
                     61:  */
                     62: 
                     63:   #define TEMPHOOK             "temphook"
                     64:   #define MAX_IFACE_CREATE     128
                     65: 
                     66:   /* Set menu options */
                     67:   enum {
                     68:     SET_PEER,
                     69:     SET_SELF,
                     70:     SET_TIMEOUTS,
                     71: #if NGM_NETFLOW_COOKIE >= 1309868867
                     72:     SET_TEMPLATE,
                     73:     SET_MTU,
                     74:     SET_VERSION,
                     75: #endif
                     76:     SET_NODE,
                     77:     SET_HOOK
                     78:   };
                     79: 
                     80: /*
                     81:  * INTERNAL FUNCTIONS
                     82:  */
                     83: 
                     84: #ifdef USE_NG_NETFLOW
                     85:   static int   NetflowSetCommand(Context ctx, int ac, char *av[], void *arg);
                     86: #endif
                     87: 
                     88: /*
                     89:  * GLOBAL VARIABLES
                     90:  */
                     91: 
                     92: #ifdef USE_NG_NETFLOW
                     93:   const struct cmdtab NetflowSetCmds[] = {
                     94:     { "peer {ip} {port}",      "Set export destination" ,
                     95:         NetflowSetCommand, NULL, 2, (void *) SET_PEER },
                     96:     { "self {ip} [{port}]",    "Set export source" ,
                     97:         NetflowSetCommand, NULL, 2, (void *) SET_SELF },
                     98:     { "timeouts {inactive} {active}", "Set NetFlow timeouts" ,
                     99:         NetflowSetCommand, NULL, 2, (void *) SET_TIMEOUTS },
                    100: #if NGM_NETFLOW_COOKIE >= 1309868867
                    101:     { "template {time} {packets}", "Set NetFlow v9 template" ,
                    102:         NetflowSetCommand, NULL, 2, (void *) SET_TEMPLATE },
                    103:     { "mtu {mtu}", "Set NetFlow v9 MTU" ,
                    104:         NetflowSetCommand, NULL, 2, (void *) SET_MTU },
                    105:     { "version {version}", "Set version to export" ,
                    106:         NetflowSetCommand, NULL, 2, (void *) SET_VERSION },
                    107: #endif
                    108:     { "node {name}", "Set node name to use" ,
                    109:         NetflowSetCommand, NULL, 2, (void *) SET_NODE },
                    110:     { "hook {number}", "Set initial hook number" ,
                    111:         NetflowSetCommand, NULL, 2, (void *) SET_HOOK },
                    112:     { NULL },
                    113:   };
                    114: #endif
                    115: 
                    116: /*
                    117:  * INTERNAL VARIABLES
                    118:  */
                    119: 
                    120: #ifdef USE_NG_TCPMSS
                    121:   u_char gTcpMSSNode = FALSE;
                    122: #endif
                    123: #ifdef USE_NG_NETFLOW
                    124:   u_char gNetflowNode = FALSE;
                    125:   u_char gNetflowNodeShutdown = TRUE;
                    126:   char gNetflowNodeName[64] = "mpd-nf";
                    127:   ng_ID_t gNetflowNodeID = 0;
                    128:   u_int gNetflowIface = 0;
                    129:   struct sockaddr_storage gNetflowExport;
                    130:   struct sockaddr_storage gNetflowSource;
                    131:   uint32_t gNetflowInactive = 0;
                    132:   uint32_t gNetflowActive = 0;
                    133: #if NGM_NETFLOW_COOKIE >= 1309868867
                    134:   uint16_t gNetflowTime = 0;
                    135:   uint16_t gNetflowPackets = 0;
                    136:   uint16_t gNetflowMTU = 0;
                    137:   u_int gNetflowVer = 5;
                    138: #endif
                    139: #endif
                    140:   
                    141:   static int   gNgStatSock=0;
                    142: 
                    143: 
                    144: #ifdef USE_NG_NETFLOW
                    145: int
                    146: NgFuncInitGlobalNetflow(void)
                    147: {
                    148:     char               path[NG_PATHSIZ];
                    149:     struct ngm_mkpeer  mp;
                    150:     struct ngm_rmhook  rm;
                    151:     struct ngm_name    nm;
                    152:     int                        csock;
                    153: 
                    154:     /* Create a netgraph socket node */
                    155:     if (NgMkSockNode(NULL, &csock, NULL) < 0) {
                    156:        Perror("NETFLOW: Can't create %s node", NG_SOCKET_NODE_TYPE);
                    157:         return (-1);
                    158:     }
                    159: 
                    160:     /* If node exist just get it's ID. */
                    161:     if (gNetflowNode) {
                    162:        snprintf(path, sizeof(path), "%s:", gNetflowNodeName);
                    163:        gNetflowNodeID = NgGetNodeID(csock, path);
                    164:        close(csock);
                    165:        return (0);
                    166:     }
                    167: 
                    168:     snprintf(gNetflowNodeName, sizeof(gNetflowNodeName), "mpd%d-nf", gPid);
                    169: 
                    170:     /* Create a global netflow node. */
                    171:     strcpy(mp.type, NG_NETFLOW_NODE_TYPE);
                    172:     strcpy(mp.ourhook, TEMPHOOK);
                    173:     strcpy(mp.peerhook, NG_NETFLOW_HOOK_DATA "0");
                    174:     if (NgSendMsg(csock, ".:",
                    175:       NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
                    176:        Perror("NETFLOW: Can't create %s node at \"%s\"->\"%s\"", 
                    177:            mp.type, ".:", mp.ourhook);
                    178:        goto fail;
                    179:     }
                    180:     
                    181:     /* Get new node ID. */
                    182:     gNetflowNodeID = NgGetNodeID(csock, TEMPHOOK);
                    183: 
                    184:     /* Set the new node's name. */
                    185:     strcpy(nm.name, gNetflowNodeName);
                    186:     if (NgSendMsg(csock, TEMPHOOK,
                    187:       NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
                    188:        Perror("NETFLOW: Can't name %s node", NG_NETFLOW_NODE_TYPE);
                    189:        goto fail;
                    190:     }
                    191: 
                    192:     /* Connect ng_ksocket(4) node for export. */
                    193:     strcpy(mp.type, NG_KSOCKET_NODE_TYPE);
                    194: #if NGM_NETFLOW_COOKIE >= 1309868867
                    195:     if (gNetflowVer == 5) {
                    196: #endif
                    197:        strcpy(mp.ourhook, NG_NETFLOW_HOOK_EXPORT);
                    198: #if NGM_NETFLOW_COOKIE >= 1309868867
                    199:     } else {
                    200:        strcpy(mp.ourhook, NG_NETFLOW_HOOK_EXPORT9);
                    201:     }
                    202: #endif
                    203:     if (gNetflowExport.ss_family==AF_INET6) {
                    204:        snprintf(mp.peerhook, sizeof(mp.peerhook), "%d/%d/%d", PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
                    205:     } else {
                    206:         snprintf(mp.peerhook, sizeof(mp.peerhook), "inet/dgram/udp");
                    207:     }
                    208:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
                    209:     if (NgSendMsg(csock, path,
                    210:       NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
                    211:        Perror("NETFLOW: Can't create %s node at \"%s\"->\"%s\"",
                    212:            mp.type, path, mp.ourhook);
                    213:        goto fail;
                    214:     }
                    215: 
                    216:     /* Configure timeouts for ng_netflow(4). */
                    217:     if (gNetflowInactive != 0 && gNetflowActive != 0) {
                    218:        struct ng_netflow_settimeouts nf_settime;
                    219: 
                    220:        nf_settime.inactive_timeout = gNetflowInactive;
                    221:        nf_settime.active_timeout = gNetflowActive;
                    222: 
                    223:        if (NgSendMsg(csock, path, NGM_NETFLOW_COOKIE,
                    224:          NGM_NETFLOW_SETTIMEOUTS, &nf_settime, sizeof(nf_settime)) < 0) {
                    225:            Perror("NETFLOW: Can't set timeouts on netflow %s node",
                    226:                NG_NETFLOW_NODE_TYPE);
                    227:            goto fail2;
                    228:        }
                    229:     }
                    230: 
                    231: #if NGM_NETFLOW_COOKIE >= 1309868867
                    232:     if (gNetflowTime != 0 && gNetflowPackets != 0) {
                    233:        struct ng_netflow_settemplate nf_settempl;
                    234: 
                    235:        nf_settempl.time = gNetflowTime;
                    236:        nf_settempl.packets = gNetflowPackets;
                    237:        if (NgSendMsg(csock, path, NGM_NETFLOW_COOKIE,
                    238:          NGM_NETFLOW_SETTEMPLATE, &nf_settempl, sizeof(nf_settempl)) < 0) {
                    239:            Perror("NETFLOW: Can't set NetFlow v9 template on netflow %s node",
                    240:                NG_NETFLOW_NODE_TYPE);
                    241:            goto fail2;
                    242:        }
                    243:     }
                    244: 
                    245:     if (gNetflowMTU != 0) {
                    246:        struct ng_netflow_setmtu nf_setmtu;
                    247: 
                    248:        nf_setmtu.mtu = gNetflowMTU;
                    249:        if (NgSendMsg(csock, path, NGM_NETFLOW_COOKIE,
                    250:          NGM_NETFLOW_SETMTU, &nf_setmtu, sizeof(nf_setmtu)) < 0) {
                    251:            Perror("NETFLOW: Can't set NetFlow v9 MTU on netflow %s node",
                    252:                NG_NETFLOW_NODE_TYPE);
                    253:          goto fail2;
                    254:        }
                    255:     }
                    256: #endif
                    257: 
                    258:     /* Configure export destination and source on ng_ksocket(4). */
                    259: #if NGM_NETFLOW_COOKIE >= 1309868867
                    260:     if (gNetflowVer == 5) {
                    261: #endif
                    262:        strlcat(path, NG_NETFLOW_HOOK_EXPORT, sizeof(path));
                    263: #if NGM_NETFLOW_COOKIE >= 1309868867
                    264:     } else {
                    265:        strlcat(path, NG_NETFLOW_HOOK_EXPORT9, sizeof(path));
                    266:     }
                    267: #endif
                    268:     if (gNetflowSource.ss_len != 0) {
                    269:        if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
                    270:          NGM_KSOCKET_BIND, &gNetflowSource, sizeof(gNetflowSource)) < 0) {
                    271:            Perror("NETFLOW: Can't bind export %s node", NG_KSOCKET_NODE_TYPE);
                    272:            goto fail2;
                    273:        }
                    274:     }
                    275:     if (gNetflowExport.ss_len != 0) {
                    276:        if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
                    277:          NGM_KSOCKET_CONNECT, &gNetflowExport, sizeof(gNetflowExport)) < 0) {
                    278:            Perror("NETFLOW: Can't connect export %s node", NG_KSOCKET_NODE_TYPE);
                    279:            goto fail2;
                    280:        }
                    281:     }
                    282: 
                    283:     /* Set the new node's name. */
                    284:     snprintf(nm.name, sizeof(nm.name), "mpd%d-nfso", gPid);
                    285:     if (NgSendMsg(csock, path,
                    286:       NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
                    287:        Perror("NETFLOW: Can't name %s node", NG_KSOCKET_NODE_TYPE);
                    288:        goto fail2;
                    289:     }
                    290: 
                    291:     /* Disconnect temporary hook. */
                    292:     memset(&rm, 0, sizeof(rm));
                    293:     strncpy(rm.ourhook, TEMPHOOK, sizeof(rm.ourhook));
                    294:     if (NgSendMsg(csock, ".:",
                    295:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
                    296:        Perror("can't remove hook %s", TEMPHOOK);
                    297:        goto fail2;
                    298:     }
                    299:     gNetflowNode = TRUE;
                    300:     close(csock);
                    301: 
                    302:     return (0);
                    303: fail2:
                    304:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
                    305:     NgFuncShutdownNode(csock, "netflow", path);
                    306: fail:
                    307:     gNetflowNodeID = 0;
                    308:     close(csock);
                    309:     return (-1);
                    310: }
                    311: #endif
                    312: 
                    313: /*
                    314:  * NgFuncCreateIface()
                    315:  *
                    316:  * Create a new netgraph interface.
                    317:  */
                    318: 
                    319: int
                    320: NgFuncCreateIface(Bund b, char *buf, int max)
                    321: {
                    322:     union {
                    323:         u_char         buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
                    324:         struct ng_mesg reply;
                    325:     }                  u;
                    326:     struct nodeinfo    *const ni = (struct nodeinfo *)(void *)u.reply.data;
                    327:     struct ngm_rmhook  rm;
                    328:     struct ngm_mkpeer  mp;
                    329:     int                        rtn = 0;
                    330: 
                    331:     /* Create iface node (as a temporary peer of the socket node) */
                    332:     strcpy(mp.type, NG_IFACE_NODE_TYPE);
                    333:     strcpy(mp.ourhook, TEMPHOOK);
                    334:     strcpy(mp.peerhook, NG_IFACE_HOOK_INET);
                    335:     if (NgSendMsg(gLinksCsock, ".:",
                    336:       NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
                    337:        Log(LG_ERR, ("[%s] can't create %s node at \"%s\"->\"%s\": %s %d",
                    338:            b->name, NG_IFACE_NODE_TYPE, ".:", mp.ourhook, strerror(errno), gLinksCsock));
                    339:        return(-1);
                    340:     }
                    341: 
                    342:     /* Get the new node's name */
                    343:     if (NgSendMsg(gLinksCsock, TEMPHOOK,
                    344:       NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) {
                    345:        Perror("[%s] %s", b->name, "NGM_NODEINFO");
                    346:        rtn = -1;
                    347:        goto done;
                    348:     }
                    349:     if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
                    350:        Perror("[%s] reply from %s", b->name, NG_IFACE_NODE_TYPE);
                    351:        rtn = -1;
                    352:        goto done;
                    353:     }
                    354:     strlcpy(buf, ni->name, max);
                    355: 
                    356: done:
                    357:     /* Disconnect temporary hook */
                    358:     strcpy(rm.ourhook, TEMPHOOK);
                    359:     if (NgSendMsg(gLinksCsock, ".:",
                    360:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
                    361:        Perror("[%s] can't remove hook %s", b->name, TEMPHOOK);
                    362:        rtn = -1;
                    363:     }
                    364: 
                    365:     /* Done */
                    366:     return(rtn);
                    367: }
                    368: 
                    369: /*
                    370:  * NgFuncShutdownGlobal()
                    371:  *
                    372:  * Shutdown nodes, that are shared between bundles.
                    373:  */
                    374: 
                    375: void
                    376: NgFuncShutdownGlobal(void)
                    377: {
                    378: #ifdef USE_NG_NETFLOW
                    379:     char       path[NG_PATHSIZ];
                    380:     int                csock;
                    381: 
                    382:     if (gNetflowNode == FALSE || gNetflowNodeShutdown==FALSE)
                    383:        return;
                    384: 
                    385:     /* Create a netgraph socket node */
                    386:     if (NgMkSockNode(NULL, &csock, NULL) < 0) {
                    387:        Perror("NgFuncShutdownGlobal: can't create %s node", NG_SOCKET_NODE_TYPE);
                    388:        return;
                    389:     }
                    390: 
                    391:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
                    392:     NgFuncShutdownNode(csock, "netflow", path);
                    393:     
                    394:     close(csock);
                    395: #endif
                    396: }
                    397: 
                    398: /*
                    399:  * NgFuncShutdownNode()
                    400:  */
                    401: 
                    402: int
                    403: NgFuncShutdownNode(int csock, const char *label, const char *path)
                    404: {
                    405:     int rtn, retry = 10, delay = 1000;
                    406: 
                    407: retry:
                    408:     if ((rtn = NgSendMsg(csock, path,
                    409:       NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0)) < 0) {
                    410:        if (errno == ENOBUFS && retry > 0) {
                    411:            Log(LG_ERR, ("[%s] shutdown \"%s\": %s, retrying...",
                    412:              label, path, strerror(errno)));
                    413:            usleep(delay);
                    414:            retry--;
                    415:            delay *= 2;
                    416:            goto retry;
                    417:        }
                    418:        if (errno != ENOENT) {
                    419:            Perror("[%s] can't shutdown \"%s\"", label, path);
                    420:        }
                    421:     }
                    422:     return(rtn);
                    423: }
                    424: 
                    425: /*
                    426:  * NgFuncSetConfig()
                    427:  */
                    428: 
                    429: void
                    430: NgFuncSetConfig(Bund b)
                    431: {
                    432:     char       path[NG_PATHSIZ];
                    433:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
                    434:     if (NgSendMsg(gLinksCsock, path, NGM_PPP_COOKIE,
                    435:            NGM_PPP_SET_CONFIG, &b->pppConfig, sizeof(b->pppConfig)) < 0) {
                    436:        Perror("[%s] can't config %s", b->name, path);
                    437:        DoExit(EX_ERRDEAD);
                    438:     }
                    439: }
                    440: 
                    441: /*
                    442:  * NgFuncSendQuery()
                    443:  */
                    444: 
                    445: int
                    446: NgFuncSendQuery(const char *path, int cookie, int cmd, const void *args,
                    447:        size_t arglen, struct ng_mesg *rbuf, size_t replen, char *raddr)
                    448: {
                    449: 
                    450:     if (!gNgStatSock) {
                    451:        char            name[NG_NODESIZ];
                    452:        
                    453:        /* Create a netgraph socket node */
                    454:        snprintf(name, sizeof(name), "mpd%d-stats", gPid);
                    455:        if (NgMkSockNode(name, &gNgStatSock, NULL) < 0) {
                    456:            Perror("NgFuncSendQuery: can't create %s node", NG_SOCKET_NODE_TYPE);
                    457:            return(-1);
                    458:        }
                    459:        (void) fcntl(gNgStatSock, F_SETFD, 1);
                    460:     }
                    461: 
                    462:     /* Send message */
1.1.1.2   misho     463:     if (NgSendMsg(gNgStatSock, path, cookie, cmd, args, arglen) < 0) {
                    464:        Perror("NgFuncSendQuery: can't send message");
1.1       misho     465:        return (-1);
1.1.1.2   misho     466:     }
1.1       misho     467: 
                    468:     /* Read message */
                    469:     if (NgRecvMsg(gNgStatSock, rbuf, replen, raddr) < 0) {
                    470:        Perror("NgFuncSendQuery: can't read unexpected message");
                    471:        return (-1);
                    472:     }
                    473: 
                    474:     return (0);
                    475: }
                    476: 
                    477: /*
                    478:  * NgFuncConnect()
                    479:  */
                    480: 
                    481: int
                    482: NgFuncConnect(int csock, char *label, const char *path, const char *hook,
                    483:        const char *path2, const char *hook2)
                    484: {
                    485:     struct ngm_connect cn;
                    486: 
                    487:     strlcpy(cn.path, path2, sizeof(cn.path));
                    488:     strlcpy(cn.ourhook, hook, sizeof(cn.ourhook));
                    489:     strlcpy(cn.peerhook, hook2, sizeof(cn.peerhook));
                    490:     if (NgSendMsg(csock, path,
                    491:       NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
                    492:        Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
                    493:            label, path, hook, path2, hook2);
                    494:        return(-1);
                    495:     }
                    496:     return(0);
                    497: }
                    498: 
                    499: /*
                    500:  * NgFuncDisconnect()
                    501:  */
                    502: 
                    503: int
                    504: NgFuncDisconnect(int csock, char *label, const char *path, const char *hook)
                    505: {
                    506:     struct ngm_rmhook  rm;
                    507:     int                retry = 10, delay = 1000;
                    508: 
                    509:     /* Disconnect hook */
                    510:     memset(&rm, 0, sizeof(rm));
                    511:     strlcpy(rm.ourhook, hook, sizeof(rm.ourhook));
                    512: retry:
                    513:     if (NgSendMsg(csock, path,
                    514:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
                    515:        if (errno == ENOBUFS && retry > 0) {
                    516:            Log(LG_ERR, ("[%s] remove hook %s from node \"%s\": %s, retrying...",
                    517:              label, hook, path, strerror(errno)));
                    518:            usleep(delay);
                    519:            retry--;
                    520:            delay *= 2;
                    521:            goto retry;
                    522:        }
                    523:        Perror("[%s] can't remove hook %s from node \"%s\"", label, hook, path);
                    524:        return(-1);
                    525:     }
                    526:     return(0);
                    527: }
                    528: 
                    529: /*
                    530:  * NgFuncWritePppFrame()
                    531:  *
                    532:  * Consumes the mbuf.
                    533:  */
                    534: 
                    535: int
                    536: NgFuncWritePppFrame(Bund b, int linkNum, int proto, Mbuf bp)
                    537: {
                    538:     u_int16_t  temp;
                    539: 
                    540:     /* Prepend ppp node bypass header */
                    541:     temp = htons(linkNum);
                    542:     bp = mbcopyback(bp, -4, &temp, 2);
                    543:     temp = htons(proto);
                    544:     bp = mbcopyback(bp, 2, &temp, 2);
                    545: 
                    546:     /* Debugging */
                    547:     LogDumpBp(LG_FRAME, bp,
                    548:        "[%s] xmit bypass frame link=%d proto=0x%04x",
                    549:        b->name, (int16_t)linkNum, proto);
                    550: 
                    551:     if ((linkNum == NG_PPP_BUNDLE_LINKNUM && b->n_up == 0) ||
                    552:        (linkNum != NG_PPP_BUNDLE_LINKNUM &&
                    553:            (b->links[linkNum] == NULL ||
                    554:            b->links[linkNum]->state != PHYS_STATE_UP))) {
                    555:        Log(LG_FRAME, ("[%s] Bundle: No links ready to send packet", b->name));
                    556:        mbfree(bp);
                    557:        return (-1);
                    558:     }
                    559: 
                    560:     /* Write frame */
                    561:     return NgFuncWriteFrame(gLinksDsock, b->hook, b->name, bp);
                    562: }
                    563: 
                    564: /*
                    565:  * NgFuncWritePppFrameLink()
                    566:  *
                    567:  * Consumes the mbuf.
                    568:  */
                    569: 
                    570: int
                    571: NgFuncWritePppFrameLink(Link l, int proto, Mbuf bp)
                    572: {
                    573:     u_int16_t  temp;
                    574: 
                    575:     if (l->joined_bund) {
                    576:        return (NgFuncWritePppFrame(l->bund, l->bundleIndex, proto, bp));
                    577:     }
                    578: 
                    579:     /* Prepend framing */
                    580:     temp = htons(0xff03);
                    581:     bp = mbcopyback(bp, -4, &temp, 2);
                    582:     temp = htons(proto);
                    583:     bp = mbcopyback(bp, 2, &temp, 2);
                    584: 
                    585:     /* Debugging */
                    586:     LogDumpBp(LG_FRAME, bp,
                    587:        "[%s] xmit frame to link proto=0x%04x",
                    588:        l->name, proto);
                    589: 
                    590:     if (l->state != PHYS_STATE_UP) {
                    591:        Log(LG_FRAME, ("[%s] Link: Not ready to send packet", l->name));
                    592:        mbfree(bp);
                    593:        return (-1);
                    594:     }
                    595: 
                    596:     /* Write frame */
                    597:     return NgFuncWriteFrame(gLinksDsock, l->hook, l->name, bp);
                    598: }
                    599: 
                    600: /*
                    601:  * NgFuncWriteFrame()
                    602:  *
                    603:  * Consumes the mbuf.
                    604:  */
                    605: 
                    606: int
                    607: NgFuncWriteFrame(int dsock, const char *hookname, const char *label, Mbuf bp)
                    608: {
                    609:     union {
                    610:         u_char          buf[sizeof(struct sockaddr_ng) + NG_HOOKSIZ];
                    611:        struct sockaddr_ng sa_ng;
                    612:     }                   u;
                    613:     struct sockaddr_ng *ng = &u.sa_ng;
                    614:     int                        rtn;
                    615: 
                    616:     /* Write frame */
                    617:     if (bp == NULL)  
                    618:        return (-1);
                    619: 
                    620:     /* Set dest address */
                    621:     memset(&u.buf, 0, sizeof(u.buf));
                    622:     strlcpy(ng->sg_data, hookname, NG_HOOKSIZ);
                    623:     ng->sg_family = AF_NETGRAPH;
                    624:     ng->sg_len = 3 + strlen(ng->sg_data);
                    625: 
                    626:     rtn = sendto(dsock, MBDATAU(bp), MBLEN(bp),
                    627:        0, (struct sockaddr *)ng, ng->sg_len);
                    628: 
                    629:     /* ENOBUFS can be expected on some links, e.g., ng_pptpgre(4) */
                    630:     if (rtn < 0 && errno != ENOBUFS) {
                    631:        Perror("[%s] error writing len %d frame to %s",
1.1.1.3 ! misho     632:            label, (int)MBLEN(bp), hookname);
1.1       misho     633:     }
                    634:     mbfree(bp);
                    635:     return (rtn);
                    636: }
                    637: 
                    638: /*
                    639:  * NgFuncClrStats()
                    640:  *
                    641:  * Clear link or whole bundle statistics
                    642:  */
                    643: 
                    644: int
                    645: NgFuncClrStats(Bund b, u_int16_t linkNum)
                    646: {
                    647:     char       path[NG_PATHSIZ];
                    648: 
                    649:     /* Get stats */
                    650:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
                    651:     if (NgSendMsg(gLinksCsock, path, 
                    652:        NGM_PPP_COOKIE, NGM_PPP_CLR_LINK_STATS, &linkNum, sizeof(linkNum)) < 0) {
                    653:            Perror("[%s] can't clear stats, link=%d", b->name, linkNum);
                    654:            return (-1);
                    655:     }
                    656:     return(0);
                    657: }
                    658: 
                    659: /*
                    660:  * NgFuncGetStats()
                    661:  *
                    662:  * Get link or whole bundle statistics
                    663:  */
                    664: 
                    665: int
                    666: NgFuncGetStats(Bund b, u_int16_t linkNum, struct ng_ppp_link_stat *statp)
                    667: {
                    668:     union {
                    669:         u_char                 buf[sizeof(struct ng_mesg)
                    670:                                  + sizeof(struct ng_ppp_link_stat)];
                    671:         struct ng_mesg         reply;
                    672:     }                          u;
                    673:     char                       path[NG_PATHSIZ];
                    674: 
                    675:     /* Get stats */
                    676:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
                    677:     if (NgFuncSendQuery(path, NGM_PPP_COOKIE, NGM_PPP_GET_LINK_STATS,
                    678:       &linkNum, sizeof(linkNum), &u.reply, sizeof(u), NULL) < 0) {
                    679:        Perror("[%s] can't get stats, link=%d", b->name, linkNum);
                    680:        return -1;
                    681:     }
                    682:     if (statp != NULL)
                    683:        memcpy(statp, u.reply.data, sizeof(*statp));
                    684:     return(0);
                    685: }
                    686: 
                    687: #ifdef NG_PPP_STATS64
                    688: /*
                    689:  * NgFuncGetStats64()
                    690:  *
                    691:  * Get 64bit link or whole bundle statistics
                    692:  */
                    693: 
                    694: int
                    695: NgFuncGetStats64(Bund b, u_int16_t linkNum, struct ng_ppp_link_stat64 *statp)
                    696: {
                    697:     union {
                    698:         u_char                 buf[sizeof(struct ng_mesg)
                    699:                                  + sizeof(struct ng_ppp_link_stat64)];
                    700:         struct ng_mesg         reply;
                    701:     }                          u;
                    702:     char                       path[NG_PATHSIZ];
                    703: 
                    704:     /* Get stats */
                    705:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
                    706:     if (NgFuncSendQuery(path, NGM_PPP_COOKIE, NGM_PPP_GET_LINK_STATS64,
                    707:       &linkNum, sizeof(linkNum), &u.reply, sizeof(u), NULL) < 0) {
                    708:        Perror("[%s] can't get stats, link=%d", b->name, linkNum);
                    709:        return -1;
                    710:     }
                    711:     if (statp != NULL)
                    712:        memcpy(statp, u.reply.data, sizeof(*statp));
                    713:     return(0);
                    714: }
                    715: #endif
                    716: 
                    717: /*
                    718:  * NgFuncErrx()
                    719:  */
                    720: 
                    721: void
                    722: NgFuncErrx(const char *fmt, ...)
                    723: {
                    724:     char       buf[100];
                    725:     va_list    args;
                    726: 
                    727:     va_start(args, fmt);
                    728:     vsnprintf(buf, sizeof(buf), fmt, args);
                    729:     va_end(args);
                    730:     Log(LG_ERR, ("netgraph: %s", buf));
                    731: }
                    732: 
                    733: /*
                    734:  * NgFuncErr()
                    735:  */
                    736: 
                    737: void
                    738: NgFuncErr(const char *fmt, ...)
                    739: {
                    740:     char       buf[100];
                    741:     va_list    args;
                    742: 
                    743:     va_start(args, fmt);
                    744:     vsnprintf(buf, sizeof(buf), fmt, args);
                    745:     va_end(args);
                    746:     Perror("netgraph: %s", buf);
                    747: }
                    748: 
                    749: #ifdef USE_NG_NETFLOW
                    750: /*
                    751:  * NetflowSetCommand()
                    752:  */
                    753:        
                    754: static int
                    755: NetflowSetCommand(Context ctx, int ac, char *av[], void *arg)
                    756: {
                    757:     struct sockaddr_storage *sin;
                    758: 
                    759:     switch ((intptr_t)arg) {
                    760:        case SET_PEER: 
                    761:            if (ac != 2)
                    762:                return (-1);
                    763:            if ((sin = ParseAddrPort(ac, av, ALLOW_IPV4|ALLOW_IPV6)) == NULL)
                    764:                return (-1);
                    765:            gNetflowExport = *sin;
                    766:            break;
                    767:        case SET_SELF:
1.1.1.3 ! misho     768:            if (ac != 1 && ac != 2)
        !           769:                return (-1);
1.1       misho     770:            if ((sin = ParseAddrPort(ac, av, ALLOW_IPV4|ALLOW_IPV6)) == NULL)
                    771:                return (-1);
                    772:            gNetflowSource = *sin;
                    773:            break;
                    774:        case SET_TIMEOUTS:
                    775:            if (ac != 2)
                    776:                return (-1);
                    777:            if (atoi(av[0]) <= 0 || atoi(av[1]) <= 0)
                    778:                Error("Bad netflow timeouts \"%s %s\"", av[0], av[1]);
                    779:            gNetflowInactive = atoi(av[0]);
                    780:            gNetflowActive = atoi(av[1]);
                    781:            break;
                    782: #if NGM_NETFLOW_COOKIE >= 1309868867
                    783:        case SET_TEMPLATE:
                    784:            if (ac != 2)
                    785:                return (-1);
                    786:            /*
                    787:             * RFC 3954 clause 7.3
                    788:             * "Both options MUST be configurable by the user on the Exporter."
                    789:             */
                    790:            if (atoi(av[0]) <= 0 || atoi(av[1]) <= 0)
                    791:                Error("Bad netflow v9 template values \"%s %s\"", av[0], av[1]);
                    792:            gNetflowTime = atoi(av[0]);         /* Default 600 */
                    793:            gNetflowPackets = atoi(av[1]);      /* Default 500 */
                    794:            break;
                    795:        case SET_MTU:
                    796:            if (ac != 1)
                    797:                return (-1);
                    798:            if (atoi(av[0]) < MIN_MTU || atoi(av[0]) > MAX_MTU)
                    799:                Error("Bad netflow v9 MTU \"%s\"", av[0]);
                    800:            gNetflowMTU = atoi(av[0]);          /* Default 1500 */
                    801:            break;
                    802:        case SET_VERSION:
                    803:            if (ac != 1)
                    804:                return (-1);
                    805:            if (atoi(av[0]) != 5 && atoi(av[0]) != 9)
                    806:                Error("Bad netflow export version \"%s\"", av[0]);
                    807:            gNetflowVer = atoi(av[0]);          /* Default 5 */
                    808:            break;
                    809: #endif
                    810:        case SET_NODE:
                    811:            if (ac != 1)
                    812:                return (-1);
                    813:            if (strlen(av[0]) == 0 || strlen(av[0]) > 63)
                    814:                Error("Bad netflow node name \"%s\"", av[0]);
                    815:            strlcpy(gNetflowNodeName, av[0], sizeof(gNetflowNodeName));
                    816:            gNetflowNode=TRUE;
                    817:            gNetflowNodeShutdown=FALSE;
                    818:            break;
                    819:        case SET_HOOK:
                    820:            if (ac != 1)
                    821:                return (-1);
1.1.1.3 ! misho     822:            if (atoi(av[0]) <= 0 || atoi(av[0]) >= NG_NETFLOW_MAXIFACES)
1.1       misho     823:                Error("Bad netflow hook number \"%s\"", av[0]);
                    824:            gNetflowIface = atoi(av[0])-1;
                    825:            break;
                    826: 
                    827:        default:
                    828:            return (-1);
                    829:     }
                    830: 
                    831:     return (0);
                    832: }
1.1.1.2   misho     833: 
                    834: /*
                    835:  * ShowNetflow()
                    836:  *
                    837:  * Show state of a Netflow
                    838:  */
                    839: 
                    840: int
                    841: ShowNetflow(Context ctx, int ac, char *av[], void *arg)
                    842: {
                    843:     struct u_addr addr;
                    844:     in_port_t port;
                    845:     char buf[64];
                    846:     char path[NG_PATHSIZ];
                    847:     union {
                    848:         u_char buf[sizeof(struct ng_mesg) + sizeof(struct ng_netflow_info)];
                    849:         struct ng_mesg reply;
                    850:     } u;
                    851:     struct ng_netflow_info *const ni = \
                    852:         (struct ng_netflow_info *)(void *)u.reply.data;
                    853: #ifdef NGM_NETFLOW_V9_COOKIE
                    854:     union {
                    855:         u_char buf[sizeof(struct ng_mesg) + sizeof(struct ng_netflow_v9info)];
                    856:         struct ng_mesg reply;
                    857:     } uv9;
                    858:     struct ng_netflow_v9info *const niv9 = \
                    859:         (struct ng_netflow_v9info *)(void *)uv9.reply.data;
                    860: #endif /* NGM_NETFLOW_V9_COOKIE */
                    861: 
                    862:     if (gNetflowNodeID>0) {
                    863:         snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
                    864:         if (NgFuncSendQuery(path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_INFO,
                    865:         NULL, 0, &u.reply, sizeof(u), NULL) < 0)
                    866:             return(-7);
                    867: #ifdef NGM_NETFLOW_V9_COOKIE
                    868:         if (NgFuncSendQuery(path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_V9INFO,
                    869:         NULL, 0, &uv9.reply, sizeof(uv9), NULL) < 0)
                    870:             return(-7);
                    871: #endif /* NGM_NETFLOW_V9_COOKIE */
                    872:     }
                    873: 
                    874:     Printf("Netflow status:\r\n");
                    875:     Printf("\tNode created   : %s\r\n", gNetflowNodeID ? "Yes" : "No");
                    876:     Printf("Netflow settings:\r\n");
                    877:     Printf("\tNode name      : %s\r\n", gNetflowNodeName);
                    878:     Printf("\tInitial hook   : %d\r\n", gNetflowIface);
                    879:     Printf("\tTimeouts, sec:\r\n");
1.1.1.3 ! misho     880:     Printf("\t  Active       : %u\r\n",
1.1.1.2   misho     881:         (gNetflowNodeID>0) ? ni->nfinfo_act_t :
                    882:         (gNetflowActive ? gNetflowActive : ACTIVE_TIMEOUT));
1.1.1.3 ! misho     883:     Printf("\t  Inactive     : %u\r\n",
1.1.1.2   misho     884:         (gNetflowNodeID>0) ? ni->nfinfo_inact_t :
                    885:         (gNetflowInactive ? gNetflowInactive : INACTIVE_TIMEOUT));
                    886:     sockaddrtou_addr(&gNetflowExport, &addr, &port);
                    887:     Printf("\tExport address : %s port %d\r\n",
                    888:         u_addrtoa(&addr, buf, sizeof(buf)), (int)port);
                    889:     sockaddrtou_addr(&gNetflowSource, &addr, &port);
                    890:     Printf("\tSource address : %s port %d\r\n",
                    891:         u_addrtoa(&addr, buf, sizeof(buf)), (int)port);
                    892: #if NGM_NETFLOW_COOKIE >= 1309868867
                    893:     Printf("\tExport version : v%d\r\n", gNetflowVer);
                    894:     Printf("Netflow v9 configuration:\r\n");
                    895:     Printf("\tTemplate:\r\n");
                    896: #ifdef NGM_NETFLOW_V9_COOKIE
                    897:     Printf("\t  Time         : %d\r\n",
                    898:         (gNetflowNodeID>0) ? niv9->templ_time :
                    899:         (gNetflowTime ? gNetflowTime : NETFLOW_V9_MAX_TIME_TEMPL));
                    900:     Printf("\t  Packets      : %d\r\n",
                    901:         (gNetflowNodeID>0) ? niv9->templ_packets :
                    902:         (gNetflowPackets ? gNetflowPackets : NETFLOW_V9_MAX_PACKETS_TEMPL));
                    903:     Printf("\tNetflow v9 MTU : %d\r\n",
                    904:         (gNetflowNodeID>0) ? niv9->mtu :
                    905:         (gNetflowMTU ? gNetflowMTU : BASE_MTU));
                    906: #else
                    907:     Printf("\t  Time         : %d\r\n",
                    908:         gNetflowTime ? gNetflowTime : NETFLOW_V9_MAX_TIME_TEMPL);
                    909:     Printf("\t  Packets      : %d\r\n",
                    910:         gNetflowPackets ? gNetflowPackets : NETFLOW_V9_MAX_PACKETS_TEMPL);
                    911:     Printf("\tNetflow v9 MTU : %d\r\n",
                    912:         gNetflowMTU ? gNetflowMTU : BASE_MTU);
                    913: #endif /* NGM_NETFLOW_V9_COOKIE */
                    914: #endif
                    915:     if (gNetflowNodeID>0) {
                    916:         Printf("Traffic stats:\r\n");
1.1.1.3 ! misho     917: #if NGM_NETFLOW_COOKIE >= 1365756954
        !           918:         Printf("\tAccounted IPv4 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes);
        !           919:         Printf("\tAccounted IPv4 packets : %llu\r\n", (unsigned long long)ni->nfinfo_packets);
        !           920:         Printf("\tAccounted IPv6 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes6);
        !           921:         Printf("\tAccounted IPv6 packets : %llu\r\n", (unsigned long long)ni->nfinfo_packets6);
        !           922:         Printf("\tSkipped IPv4 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes);
        !           923:         Printf("\tSkipped IPv4 packets   : %llu\r\n", (unsigned long long)ni->nfinfo_spackets);
        !           924:         Printf("\tSkipped IPv6 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes6);
        !           925:         Printf("\tSkipped IPv6 packets   : %llu\r\n", (unsigned long long)ni->nfinfo_spackets6);
        !           926:         Printf("\tActive expiries        : %llu\r\n", (unsigned long long)ni->nfinfo_act_exp);
        !           927:         Printf("\tInactive expiries      : %llu\r\n", (unsigned long long)ni->nfinfo_inact_exp);
        !           928:         Printf("\tUsed IPv4 cache records: %u\r\n", ni->nfinfo_used);
        !           929:         Printf("\tUsed IPv6 cache records: %u\r\n", ni->nfinfo_used6);
        !           930:         Printf("\tFailed allocations     : %u\r\n", ni->nfinfo_alloc_failed);
        !           931:         Printf("\tFailed v5 export       : %u\r\n", ni->nfinfo_export_failed);
        !           932:         Printf("\tFailed v9 export       : %u\r\n", ni->nfinfo_export9_failed);
        !           933:         Printf("\tRallocated mbufs       : %u\r\n", ni->nfinfo_realloc_mbuf);
        !           934:         Printf("\tFibs allocated         : %u\r\n", ni->nfinfo_alloc_fibs);
        !           935: #else /* NGM_NETFLOW_COOKIE >= 1365756954 */
1.1.1.2   misho     936:         Printf("\tAccounted IPv4 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes);
1.1.1.3 ! misho     937:         Printf("\tAccounted IPv4 packets : %u\r\n", ni->nfinfo_packets);
1.1.1.2   misho     938: #if NGM_NETFLOW_COOKIE >= 1309868867
                    939:         Printf("\tAccounted IPv6 octets  : %llu\r\n", (unsigned long long)ni->nfinfo_bytes6);
1.1.1.3 ! misho     940:         Printf("\tAccounted IPv6 packets : %u\r\n", ni->nfinfo_packets6);
1.1.1.2   misho     941:         Printf("\tSkipped IPv4 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes);
1.1.1.3 ! misho     942:         Printf("\tSkipped IPv4 packets   : %u\r\n", ni->nfinfo_spackets);
1.1.1.2   misho     943:         Printf("\tSkipped IPv6 octets    : %llu\r\n", (unsigned long long)ni->nfinfo_sbytes6);
1.1.1.3 ! misho     944:         Printf("\tSkipped IPv6 packets   : %u\r\n", ni->nfinfo_spackets6);
1.1.1.2   misho     945: #endif
1.1.1.3 ! misho     946:         Printf("\tUsed IPv4 cache records: %u\r\n", ni->nfinfo_used);
1.1.1.2   misho     947: #if NGM_NETFLOW_COOKIE >= 1309868867
1.1.1.3 ! misho     948:         Printf("\tUsed IPv6 cache records: %u\r\n", ni->nfinfo_used6);
1.1.1.2   misho     949: #endif
1.1.1.3 ! misho     950:         Printf("\tFailed allocations     : %u\r\n", ni->nfinfo_alloc_failed);
        !           951:         Printf("\tFailed v5 export       : %u\r\n", ni->nfinfo_export_failed);
1.1.1.2   misho     952: #if NGM_NETFLOW_COOKIE >= 1309868867
1.1.1.3 ! misho     953:         Printf("\tFailed v9 export       : %u\r\n", ni->nfinfo_export9_failed);
        !           954:         Printf("\tRallocated mbufs       : %u\r\n", ni->nfinfo_realloc_mbuf);
        !           955:         Printf("\tFibs allocated         : %u\r\n", ni->nfinfo_alloc_fibs);
1.1.1.2   misho     956: #endif
1.1.1.3 ! misho     957:         Printf("\tActive expiries        : %u\r\n", ni->nfinfo_act_exp);
        !           958:         Printf("\tInactive expiries      : %u\r\n", ni->nfinfo_inact_exp);
        !           959: #endif /* NGM_NETFLOW_COOKIE >= 1365756954 */
1.1.1.2   misho     960:     }
                    961:     return(0);
                    962: }
1.1       misho     963: #endif /* USE_NG_NETFLOW */
                    964: 
                    965: ng_ID_t
                    966: NgGetNodeID(int csock, const char *path)
                    967: {
                    968:     union {
                    969:         u_char          buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
                    970:        struct ng_mesg  reply;
                    971:     }                   u;
                    972:     struct nodeinfo     *const ni = (struct nodeinfo *)(void *)u.reply.data;
                    973:     
                    974:     if (csock < 0) {
                    975:        if (!gNgStatSock) {
                    976:            char                name[NG_NODESIZ];
                    977:        
                    978:            /* Create a netgraph socket node */
                    979:            snprintf(name, sizeof(name), "mpd%d-stats", gPid);
                    980:            if (NgMkSockNode(name, &gNgStatSock, NULL) < 0) {
                    981:                Perror("NgFuncSendQuery: can't create %s node", NG_SOCKET_NODE_TYPE);
                    982:                return(-1);
                    983:            }
                    984:            (void) fcntl(gNgStatSock, F_SETFD, 1);
                    985:        }
                    986:        csock = gNgStatSock;
                    987:     }
                    988: 
                    989:     if (NgSendMsg(csock, path,
                    990:       NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0)
                    991:         return (0);
                    992:     if (NgRecvMsg(csock, &u.reply, sizeof(u), NULL) < 0)
                    993:        return (0);
                    994:     
                    995:     return (ni->id);
                    996: }
                    997: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>