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

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: #if NGM_NETFLOW_COOKIE >= 1309868867
        !            48: #include <netgraph/netflow/netflow.h>
        !            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 */
        !           463:     if (NgSendMsg(gNgStatSock, path, cookie, cmd, args, arglen) < 0)
        !           464:        return (-1);
        !           465: 
        !           466:     /* Read message */
        !           467:     if (NgRecvMsg(gNgStatSock, rbuf, replen, raddr) < 0) {
        !           468:        Perror("NgFuncSendQuery: can't read unexpected message");
        !           469:        return (-1);
        !           470:     }
        !           471: 
        !           472:     return (0);
        !           473: }
        !           474: 
        !           475: /*
        !           476:  * NgFuncConnect()
        !           477:  */
        !           478: 
        !           479: int
        !           480: NgFuncConnect(int csock, char *label, const char *path, const char *hook,
        !           481:        const char *path2, const char *hook2)
        !           482: {
        !           483:     struct ngm_connect cn;
        !           484: 
        !           485:     strlcpy(cn.path, path2, sizeof(cn.path));
        !           486:     strlcpy(cn.ourhook, hook, sizeof(cn.ourhook));
        !           487:     strlcpy(cn.peerhook, hook2, sizeof(cn.peerhook));
        !           488:     if (NgSendMsg(csock, path,
        !           489:       NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
        !           490:        Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
        !           491:            label, path, hook, path2, hook2);
        !           492:        return(-1);
        !           493:     }
        !           494:     return(0);
        !           495: }
        !           496: 
        !           497: /*
        !           498:  * NgFuncDisconnect()
        !           499:  */
        !           500: 
        !           501: int
        !           502: NgFuncDisconnect(int csock, char *label, const char *path, const char *hook)
        !           503: {
        !           504:     struct ngm_rmhook  rm;
        !           505:     int                retry = 10, delay = 1000;
        !           506: 
        !           507:     /* Disconnect hook */
        !           508:     memset(&rm, 0, sizeof(rm));
        !           509:     strlcpy(rm.ourhook, hook, sizeof(rm.ourhook));
        !           510: retry:
        !           511:     if (NgSendMsg(csock, path,
        !           512:       NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
        !           513:        if (errno == ENOBUFS && retry > 0) {
        !           514:            Log(LG_ERR, ("[%s] remove hook %s from node \"%s\": %s, retrying...",
        !           515:              label, hook, path, strerror(errno)));
        !           516:            usleep(delay);
        !           517:            retry--;
        !           518:            delay *= 2;
        !           519:            goto retry;
        !           520:        }
        !           521:        Perror("[%s] can't remove hook %s from node \"%s\"", label, hook, path);
        !           522:        return(-1);
        !           523:     }
        !           524:     return(0);
        !           525: }
        !           526: 
        !           527: /*
        !           528:  * NgFuncWritePppFrame()
        !           529:  *
        !           530:  * Consumes the mbuf.
        !           531:  */
        !           532: 
        !           533: int
        !           534: NgFuncWritePppFrame(Bund b, int linkNum, int proto, Mbuf bp)
        !           535: {
        !           536:     u_int16_t  temp;
        !           537: 
        !           538:     /* Prepend ppp node bypass header */
        !           539:     temp = htons(linkNum);
        !           540:     bp = mbcopyback(bp, -4, &temp, 2);
        !           541:     temp = htons(proto);
        !           542:     bp = mbcopyback(bp, 2, &temp, 2);
        !           543: 
        !           544:     /* Debugging */
        !           545:     LogDumpBp(LG_FRAME, bp,
        !           546:        "[%s] xmit bypass frame link=%d proto=0x%04x",
        !           547:        b->name, (int16_t)linkNum, proto);
        !           548: 
        !           549:     if ((linkNum == NG_PPP_BUNDLE_LINKNUM && b->n_up == 0) ||
        !           550:        (linkNum != NG_PPP_BUNDLE_LINKNUM &&
        !           551:            (b->links[linkNum] == NULL ||
        !           552:            b->links[linkNum]->state != PHYS_STATE_UP))) {
        !           553:        Log(LG_FRAME, ("[%s] Bundle: No links ready to send packet", b->name));
        !           554:        mbfree(bp);
        !           555:        return (-1);
        !           556:     }
        !           557: 
        !           558:     /* Write frame */
        !           559:     return NgFuncWriteFrame(gLinksDsock, b->hook, b->name, bp);
        !           560: }
        !           561: 
        !           562: /*
        !           563:  * NgFuncWritePppFrameLink()
        !           564:  *
        !           565:  * Consumes the mbuf.
        !           566:  */
        !           567: 
        !           568: int
        !           569: NgFuncWritePppFrameLink(Link l, int proto, Mbuf bp)
        !           570: {
        !           571:     u_int16_t  temp;
        !           572: 
        !           573:     if (l->joined_bund) {
        !           574:        return (NgFuncWritePppFrame(l->bund, l->bundleIndex, proto, bp));
        !           575:     }
        !           576: 
        !           577:     /* Prepend framing */
        !           578:     temp = htons(0xff03);
        !           579:     bp = mbcopyback(bp, -4, &temp, 2);
        !           580:     temp = htons(proto);
        !           581:     bp = mbcopyback(bp, 2, &temp, 2);
        !           582: 
        !           583:     /* Debugging */
        !           584:     LogDumpBp(LG_FRAME, bp,
        !           585:        "[%s] xmit frame to link proto=0x%04x",
        !           586:        l->name, proto);
        !           587: 
        !           588:     if (l->state != PHYS_STATE_UP) {
        !           589:        Log(LG_FRAME, ("[%s] Link: Not ready to send packet", l->name));
        !           590:        mbfree(bp);
        !           591:        return (-1);
        !           592:     }
        !           593: 
        !           594:     /* Write frame */
        !           595:     return NgFuncWriteFrame(gLinksDsock, l->hook, l->name, bp);
        !           596: }
        !           597: 
        !           598: /*
        !           599:  * NgFuncWriteFrame()
        !           600:  *
        !           601:  * Consumes the mbuf.
        !           602:  */
        !           603: 
        !           604: int
        !           605: NgFuncWriteFrame(int dsock, const char *hookname, const char *label, Mbuf bp)
        !           606: {
        !           607:     union {
        !           608:         u_char          buf[sizeof(struct sockaddr_ng) + NG_HOOKSIZ];
        !           609:        struct sockaddr_ng sa_ng;
        !           610:     }                   u;
        !           611:     struct sockaddr_ng *ng = &u.sa_ng;
        !           612:     int                        rtn;
        !           613: 
        !           614:     /* Write frame */
        !           615:     if (bp == NULL)  
        !           616:        return (-1);
        !           617: 
        !           618:     /* Set dest address */
        !           619:     memset(&u.buf, 0, sizeof(u.buf));
        !           620:     strlcpy(ng->sg_data, hookname, NG_HOOKSIZ);
        !           621:     ng->sg_family = AF_NETGRAPH;
        !           622:     ng->sg_len = 3 + strlen(ng->sg_data);
        !           623: 
        !           624:     rtn = sendto(dsock, MBDATAU(bp), MBLEN(bp),
        !           625:        0, (struct sockaddr *)ng, ng->sg_len);
        !           626: 
        !           627:     /* ENOBUFS can be expected on some links, e.g., ng_pptpgre(4) */
        !           628:     if (rtn < 0 && errno != ENOBUFS) {
        !           629:        Perror("[%s] error writing len %d frame to %s",
        !           630:            label, MBLEN(bp), hookname);
        !           631:     }
        !           632:     mbfree(bp);
        !           633:     return (rtn);
        !           634: }
        !           635: 
        !           636: /*
        !           637:  * NgFuncClrStats()
        !           638:  *
        !           639:  * Clear link or whole bundle statistics
        !           640:  */
        !           641: 
        !           642: int
        !           643: NgFuncClrStats(Bund b, u_int16_t linkNum)
        !           644: {
        !           645:     char       path[NG_PATHSIZ];
        !           646: 
        !           647:     /* Get stats */
        !           648:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
        !           649:     if (NgSendMsg(gLinksCsock, path, 
        !           650:        NGM_PPP_COOKIE, NGM_PPP_CLR_LINK_STATS, &linkNum, sizeof(linkNum)) < 0) {
        !           651:            Perror("[%s] can't clear stats, link=%d", b->name, linkNum);
        !           652:            return (-1);
        !           653:     }
        !           654:     return(0);
        !           655: }
        !           656: 
        !           657: /*
        !           658:  * NgFuncGetStats()
        !           659:  *
        !           660:  * Get link or whole bundle statistics
        !           661:  */
        !           662: 
        !           663: int
        !           664: NgFuncGetStats(Bund b, u_int16_t linkNum, struct ng_ppp_link_stat *statp)
        !           665: {
        !           666:     union {
        !           667:         u_char                 buf[sizeof(struct ng_mesg)
        !           668:                                  + sizeof(struct ng_ppp_link_stat)];
        !           669:         struct ng_mesg         reply;
        !           670:     }                          u;
        !           671:     char                       path[NG_PATHSIZ];
        !           672: 
        !           673:     /* Get stats */
        !           674:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
        !           675:     if (NgFuncSendQuery(path, NGM_PPP_COOKIE, NGM_PPP_GET_LINK_STATS,
        !           676:       &linkNum, sizeof(linkNum), &u.reply, sizeof(u), NULL) < 0) {
        !           677:        Perror("[%s] can't get stats, link=%d", b->name, linkNum);
        !           678:        return -1;
        !           679:     }
        !           680:     if (statp != NULL)
        !           681:        memcpy(statp, u.reply.data, sizeof(*statp));
        !           682:     return(0);
        !           683: }
        !           684: 
        !           685: #ifdef NG_PPP_STATS64
        !           686: /*
        !           687:  * NgFuncGetStats64()
        !           688:  *
        !           689:  * Get 64bit link or whole bundle statistics
        !           690:  */
        !           691: 
        !           692: int
        !           693: NgFuncGetStats64(Bund b, u_int16_t linkNum, struct ng_ppp_link_stat64 *statp)
        !           694: {
        !           695:     union {
        !           696:         u_char                 buf[sizeof(struct ng_mesg)
        !           697:                                  + sizeof(struct ng_ppp_link_stat64)];
        !           698:         struct ng_mesg         reply;
        !           699:     }                          u;
        !           700:     char                       path[NG_PATHSIZ];
        !           701: 
        !           702:     /* Get stats */
        !           703:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
        !           704:     if (NgFuncSendQuery(path, NGM_PPP_COOKIE, NGM_PPP_GET_LINK_STATS64,
        !           705:       &linkNum, sizeof(linkNum), &u.reply, sizeof(u), NULL) < 0) {
        !           706:        Perror("[%s] can't get stats, link=%d", b->name, linkNum);
        !           707:        return -1;
        !           708:     }
        !           709:     if (statp != NULL)
        !           710:        memcpy(statp, u.reply.data, sizeof(*statp));
        !           711:     return(0);
        !           712: }
        !           713: #endif
        !           714: 
        !           715: /*
        !           716:  * NgFuncErrx()
        !           717:  */
        !           718: 
        !           719: void
        !           720: NgFuncErrx(const char *fmt, ...)
        !           721: {
        !           722:     char       buf[100];
        !           723:     va_list    args;
        !           724: 
        !           725:     va_start(args, fmt);
        !           726:     vsnprintf(buf, sizeof(buf), fmt, args);
        !           727:     va_end(args);
        !           728:     Log(LG_ERR, ("netgraph: %s", buf));
        !           729: }
        !           730: 
        !           731: /*
        !           732:  * NgFuncErr()
        !           733:  */
        !           734: 
        !           735: void
        !           736: NgFuncErr(const char *fmt, ...)
        !           737: {
        !           738:     char       buf[100];
        !           739:     va_list    args;
        !           740: 
        !           741:     va_start(args, fmt);
        !           742:     vsnprintf(buf, sizeof(buf), fmt, args);
        !           743:     va_end(args);
        !           744:     Perror("netgraph: %s", buf);
        !           745: }
        !           746: 
        !           747: #ifdef USE_NG_NETFLOW
        !           748: /*
        !           749:  * NetflowSetCommand()
        !           750:  */
        !           751:        
        !           752: static int
        !           753: NetflowSetCommand(Context ctx, int ac, char *av[], void *arg)
        !           754: {
        !           755:     struct sockaddr_storage *sin;
        !           756: 
        !           757:     switch ((intptr_t)arg) {
        !           758:        case SET_PEER: 
        !           759:            if (ac != 2)
        !           760:                return (-1);
        !           761:            if ((sin = ParseAddrPort(ac, av, ALLOW_IPV4|ALLOW_IPV6)) == NULL)
        !           762:                return (-1);
        !           763:            gNetflowExport = *sin;
        !           764:            break;
        !           765:        case SET_SELF:
        !           766:            if ((sin = ParseAddrPort(ac, av, ALLOW_IPV4|ALLOW_IPV6)) == NULL)
        !           767:                return (-1);
        !           768:            gNetflowSource = *sin;
        !           769:            break;
        !           770:        case SET_TIMEOUTS:
        !           771:            if (ac != 2)
        !           772:                return (-1);
        !           773:            if (atoi(av[0]) <= 0 || atoi(av[1]) <= 0)
        !           774:                Error("Bad netflow timeouts \"%s %s\"", av[0], av[1]);
        !           775:            gNetflowInactive = atoi(av[0]);
        !           776:            gNetflowActive = atoi(av[1]);
        !           777:            break;
        !           778: #if NGM_NETFLOW_COOKIE >= 1309868867
        !           779:        case SET_TEMPLATE:
        !           780:            if (ac != 2)
        !           781:                return (-1);
        !           782:            /*
        !           783:             * RFC 3954 clause 7.3
        !           784:             * "Both options MUST be configurable by the user on the Exporter."
        !           785:             */
        !           786:            if (atoi(av[0]) <= 0 || atoi(av[1]) <= 0)
        !           787:                Error("Bad netflow v9 template values \"%s %s\"", av[0], av[1]);
        !           788:            gNetflowTime = atoi(av[0]);         /* Default 600 */
        !           789:            gNetflowPackets = atoi(av[1]);      /* Default 500 */
        !           790:            break;
        !           791:        case SET_MTU:
        !           792:            if (ac != 1)
        !           793:                return (-1);
        !           794:            if (atoi(av[0]) < MIN_MTU || atoi(av[0]) > MAX_MTU)
        !           795:                Error("Bad netflow v9 MTU \"%s\"", av[0]);
        !           796:            gNetflowMTU = atoi(av[0]);          /* Default 1500 */
        !           797:            break;
        !           798:        case SET_VERSION:
        !           799:            if (ac != 1)
        !           800:                return (-1);
        !           801:            if (atoi(av[0]) != 5 && atoi(av[0]) != 9)
        !           802:                Error("Bad netflow export version \"%s\"", av[0]);
        !           803:            gNetflowVer = atoi(av[0]);          /* Default 5 */
        !           804:            break;
        !           805: #endif
        !           806:        case SET_NODE:
        !           807:            if (ac != 1)
        !           808:                return (-1);
        !           809:            if (strlen(av[0]) == 0 || strlen(av[0]) > 63)
        !           810:                Error("Bad netflow node name \"%s\"", av[0]);
        !           811:            strlcpy(gNetflowNodeName, av[0], sizeof(gNetflowNodeName));
        !           812:            gNetflowNode=TRUE;
        !           813:            gNetflowNodeShutdown=FALSE;
        !           814:            break;
        !           815:        case SET_HOOK:
        !           816:            if (ac != 1)
        !           817:                return (-1);
        !           818:            if (atoi(av[0]) <= 0)
        !           819:                Error("Bad netflow hook number \"%s\"", av[0]);
        !           820:            gNetflowIface = atoi(av[0])-1;
        !           821:            break;
        !           822: 
        !           823:        default:
        !           824:            return (-1);
        !           825:     }
        !           826: 
        !           827:     return (0);
        !           828: }
        !           829: #endif /* USE_NG_NETFLOW */
        !           830: 
        !           831: ng_ID_t
        !           832: NgGetNodeID(int csock, const char *path)
        !           833: {
        !           834:     union {
        !           835:         u_char          buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
        !           836:        struct ng_mesg  reply;
        !           837:     }                   u;
        !           838:     struct nodeinfo     *const ni = (struct nodeinfo *)(void *)u.reply.data;
        !           839:     
        !           840:     if (csock < 0) {
        !           841:        if (!gNgStatSock) {
        !           842:            char                name[NG_NODESIZ];
        !           843:        
        !           844:            /* Create a netgraph socket node */
        !           845:            snprintf(name, sizeof(name), "mpd%d-stats", gPid);
        !           846:            if (NgMkSockNode(name, &gNgStatSock, NULL) < 0) {
        !           847:                Perror("NgFuncSendQuery: can't create %s node", NG_SOCKET_NODE_TYPE);
        !           848:                return(-1);
        !           849:            }
        !           850:            (void) fcntl(gNgStatSock, F_SETFD, 1);
        !           851:        }
        !           852:        csock = gNgStatSock;
        !           853:     }
        !           854: 
        !           855:     if (NgSendMsg(csock, path,
        !           856:       NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0)
        !           857:         return (0);
        !           858:     if (NgRecvMsg(csock, &u.reply, sizeof(u), NULL) < 0)
        !           859:        return (0);
        !           860:     
        !           861:     return (ni->id);
        !           862: }
        !           863: 

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