Annotation of fwsync/driver/fwsync.c, revision 1.12.2.2

1.11      misho       1: /*-
                      2:  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
                      3:  *
                      4:  * Copyright (c) 2022 Michael Pounov <misho@elwix.org>, CloudSigma AG
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     16:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     17:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     18:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     19:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     20:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     21:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     25:  * SUCH DAMAGE.
                     26:  */
1.1       misho      27: #include "fwsync.h"
                     28: 
                     29: 
                     30: static void
                     31: fwsync_edge_proc(void *arg)
                     32: {
1.3       misho      33:        int e, rcvflg = 0;
1.1       misho      34:        struct uio uio;
                     35:        struct mbuf *m = NULL;
1.3       misho      36:        struct fws_proto *pkt;
1.1       misho      37: 
                     38:        DTRACE();
                     39: 
1.7       misho      40:        callout_schedule(&fws_co, hz);
                     41: 
1.1       misho      42:        memset(&uio, 0, sizeof uio);
                     43:        uio.uio_resid = 1000000000;
                     44:        uio.uio_td = curthread;
                     45: 
1.7       misho      46:        if ((fws_cfg.cfg.on & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
1.1       misho      47:                rcvflg = MSG_DONTWAIT;
                     48:                e = soreceive(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], NULL, &uio, &m, NULL, &rcvflg);
                     49:                if (e) {
                     50:                        if (e != EAGAIN)
                     51:                                printf("error in edge handler #%d\n", e);
1.7       misho      52:                        return;
1.1       misho      53:                }
1.3       misho      54:                pkt = mtod(m, struct fws_proto*);
                     55:                if (m_length(m, NULL) != sizeof(struct fws_proto)) {
                     56:                        printf("FWSync packet length=%d isn't match expected %lu\n", 
                     57:                                        m_length(m, NULL), sizeof(struct fws_proto));
1.8       misho      58:                        m_freem(m);
1.7       misho      59:                        return;
1.3       misho      60:                }
1.1       misho      61: 
1.4       misho      62:                switch (pkt->fws_version) {
                     63:                        case FWS_PKTVER_STATE:
                     64:                                fwsync_add_state(pkt);
                     65:                                break;
1.5       misho      66:                        case FWS_PKTVER_ALIAS:
                     67:                                fwsync_add_alias(pkt);
1.4       misho      68:                                break;
                     69:                        default:
                     70:                                printf("FWSync packet was discarded due to wrong version\n");
1.8       misho      71:                                break;
1.4       misho      72:                }
1.8       misho      73: 
                     74:                m_freem(m);
1.1       misho      75:        }
                     76: }
                     77: 
                     78: int
                     79: fwsync_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
                     80: {
                     81:        ipfw_obj_header *oh;
                     82:        struct ipfw_sync_cfg *ucfg;
                     83:        size_t sz;
                     84:        int e;
                     85: 
                     86:        DTRACE();
                     87: 
                     88:        sz = sizeof(*oh) + sizeof(*ucfg);
                     89:        /* Check minimum header size */
                     90:        if (sd->valsize < sz)
                     91:                return (EINVAL);
                     92: 
                     93:        oh = (ipfw_obj_header*) sd->kbuf;
                     94: 
                     95:        /* Basic length checks for TLVs */
                     96:        if (oh->ntlv.head.length != sizeof(oh->ntlv))
                     97:                return (EINVAL);
                     98: 
                     99:        ucfg = (struct ipfw_sync_cfg*) (oh + 1);
                    100: 
                    101:        /* Check if name is properly terminated */
                    102:        if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
                    103:                return (EINVAL);
                    104: 
                    105:        if (ucfg->mode == CFG_SYNC_EDGE && !fws_cfg.cfg.edge && !(fws_ctx.config & CTX_CFG_EDGE) && 
                    106:                        !strcmp(ucfg->name, "edge") && ucfg->addrs == 1) {
                    107:                fws_cfg.cfg.edge = 1;
                    108:                memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE], &ucfg->addr[CFG_SYNC_ADDR_EDGE], 
                    109:                                sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE]);
                    110:                fws_ctx.config |= CTX_CFG_EDGE;
                    111: 
                    112:                e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE].addr.sa_family == AF_INET) ? AF_INET : AF_INET6, 
                    113:                                &fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
                    114:                if (e) {
                    115:                        printf("fwsync edge socreate failed #%d\n", e);
                    116:                        return e;
                    117:                }
                    118: 
                    119:                e = sobind(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], &fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE].addr, curthread);
                    120:                if (e) {
                    121:                        if (e != EADDRINUSE)
                    122:                                printf("fwsync edge sobind failed #%d\n", e);
                    123:                        else
                    124:                                printf("fwsync edge address in use!\n");
                    125:                        return e;
                    126:                } else
                    127:                        fws_ctx.config |= CTX_EDGE_READY;
                    128:        } else if (ucfg->mode == CFG_SYNC_COLLECTOR && !(fws_ctx.config & CTX_CFG_COLLECTOR_1) && 
                    129:                        !strcmp(ucfg->name, "collector") && ucfg->addrs > 0 && ucfg->addrs < 3) {
                    130:                fws_cfg.cfg.collector = 1;
                    131:                fws_cfg.cfg.addrs = ucfg->addrs;
                    132:                memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1], &ucfg->addr[CFG_SYNC_ADDR_COLLECTOR_1], 
                    133:                                sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1]);
                    134: 
                    135:                fws_ctx.config |= CTX_CFG_COLLECTOR_1;
                    136: 
                    137:                e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1].addr.sa_family == AF_INET) ? AF_INET : AF_INET6, 
                    138:                                &fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_1], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
                    139:                if (e) {
                    140:                        printf("fwsync collector %d socreate failed #%d\n", e, CFG_SYNC_ADDR_COLLECTOR_1);
                    141:                        return e;
                    142:                } else
                    143:                        fws_ctx.config |= CTX_COLLECTOR_1_READY;
                    144: 
                    145:                if (fws_cfg.cfg.addrs > 1) {
                    146:                        memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2], &ucfg->addr[CFG_SYNC_ADDR_COLLECTOR_2], 
                    147:                                        sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2]);
                    148: 
                    149:                        fws_ctx.config |= CTX_CFG_COLLECTOR_2;
                    150: 
                    151:                        e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2].addr.sa_family == AF_INET) ? AF_INET : AF_INET6, 
                    152:                                        &fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_2], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
                    153:                        if (e) {
                    154:                                printf("fwsync collector %d socreate failed #%d\n", e, CFG_SYNC_ADDR_COLLECTOR_2);
                    155:                                return e;
                    156:                        } else
                    157:                                fws_ctx.config |= CTX_COLLECTOR_2_READY;
                    158:                }
                    159:        } else
                    160:                return (EINVAL);
                    161: 
                    162:        return 0;
                    163: }
                    164: 
                    165: int
                    166: fwsync_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
                    167: {
                    168:        int *n;
                    169:        ipfw_obj_header *oh;
                    170:        size_t sz;
                    171: 
                    172:        DTRACE();
                    173: 
                    174:        sz = sizeof(*oh) + sizeof(int);
                    175:        /* Check minimum header size */
                    176:        if (sd->valsize < sz)
                    177:                return (EINVAL);
                    178: 
                    179:        oh = (ipfw_obj_header*) sd->kbuf;
                    180: 
                    181:        /* Basic length checks for TLVs */
                    182:        if (oh->ntlv.head.length != sizeof(oh->ntlv))
                    183:                return (EINVAL);
                    184: 
                    185:        n = (int*) (oh + 1);
                    186:        if (*n & CFG_SYNC_EDGE) {
1.12      misho     187:                if (fws_ctx.config & CTX_EDGE_ONLINE) {
                    188:                        ipfw_unregister_state_sync();
                    189:                        ipfw_unregister_alias_sync();
                    190:                }
                    191: 
                    192:                callout_drain(&fws_co);
                    193: 
1.1       misho     194:                fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
                    195:                fws_cfg.cfg.edge = 0;
                    196:                fws_cfg.cfg.addrs = 0;
                    197:                memset(fws_cfg.cfg_addr, 0, sizeof fws_cfg.cfg_addr[0]);
                    198: 
1.12      misho     199:                soshutdown(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SHUT_RD);
                    200:                soclose(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE]);
1.1       misho     201:        }
                    202:        if (*n & CFG_SYNC_COLLECTOR) {
                    203:                if (fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE)) {
                    204:                        ipfw_unregister_state_hook();
                    205:                        ipfw_unregister_alias_hook();
                    206:                }
                    207: 
1.8       misho     208:                taskqueue_drain(fws_tq, &fws_sndpkt_task);
                    209: 
1.1       misho     210:                fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
                    211:                fws_cfg.cfg.collector = 0;
                    212:                fws_cfg.cfg.addrs = 0;
                    213:                memset(fws_cfg.cfg_addr + 1, 0, sizeof fws_cfg.cfg_addr[0] * 2);
                    214: 
                    215:                if (fws_ctx.config & CTX_COLLECTOR_2_READY)
                    216:                        soclose(fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_2]);
                    217:                if (fws_ctx.config & CTX_COLLECTOR_1_READY)
                    218:                        soclose(fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_1]);
                    219:        }
                    220: 
                    221:        fws_ctx.config ^= fws_ctx.config;
                    222: 
1.12.2.1  misho     223:        memset(&fws_acct, 0, sizeof fws_acct);
                    224: 
1.1       misho     225:        return 0;
                    226: }
                    227: 
                    228: int
                    229: fwsync_get_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
                    230: {
                    231:        ipfw_obj_header *oh;
                    232:        struct ipfw_sync_cfg *ucfg;
                    233:        size_t sz;
                    234: 
                    235:        DTRACE();
                    236: 
                    237:        sz = sizeof(*oh) + sizeof(*ucfg);
                    238:        /* Check minimum header size */
                    239:        if (sd->valsize < sz)
                    240:                return (EINVAL);
                    241: 
                    242:        oh = (struct _ipfw_obj_header*) ipfw_get_sopt_header(sd, sz);
                    243: 
                    244:        /* Basic length checks for TLVs */
                    245:        if (oh->ntlv.head.length != sizeof(oh->ntlv))
                    246:                return (EINVAL);
                    247: 
                    248:        ucfg = (struct ipfw_sync_cfg*) (oh + 1);
                    249: 
                    250:        /* Check if name is properly terminated */
                    251:        if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
                    252:                return (EINVAL);
                    253: 
                    254:        snprintf(ucfg->name, sizeof ucfg->name, "%d", fws_cfg.cfg.on);
                    255:        ucfg->mode = 0;
                    256:        if (fws_cfg.cfg.edge)
                    257:                ucfg->mode |= CFG_SYNC_EDGE;
                    258:        if (fws_cfg.cfg.collector)
                    259:                ucfg->mode |= CFG_SYNC_COLLECTOR;
                    260:        ucfg->addrs = (fws_cfg.cfg.addrs != 1) ? fws_cfg.cfg.addrs : 1;
                    261:        memcpy(ucfg->addr, fws_cfg.cfg_addr, sizeof ucfg->addr);
                    262: 
                    263:        return 0;
                    264: }
                    265: 
                    266: int
                    267: fwsync_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
                    268: {
1.12.2.2! misho     269:        ipfw_obj_header *oh;
        !           270:        struct ipfw_sync_cfg *ucfg;
        !           271:        size_t sz;
        !           272: 
1.1       misho     273:        DTRACE();
                    274: 
1.12.2.2! misho     275:        sz = sizeof(*oh) + sizeof(*ucfg);
        !           276:        /* Check minimum header size */
        !           277:        if (sd->valsize < sz)
        !           278:                return (EINVAL);
        !           279: 
        !           280:        oh = (struct _ipfw_obj_header*) ipfw_get_sopt_header(sd, sz);
        !           281: 
        !           282:        /* Basic length checks for TLVs */
        !           283:        if (oh->ntlv.head.length != sizeof(oh->ntlv))
        !           284:                return (EINVAL);
        !           285: 
        !           286:        ucfg = (struct ipfw_sync_cfg*) (oh + 1);
        !           287: 
        !           288:        /* Check if name is properly terminated */
        !           289:        if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
        !           290:                return (EINVAL);
        !           291: 
        !           292:        ucfg->mode = 0;
        !           293:        if (fws_cfg.cfg.edge)
        !           294:                ucfg->mode |= CFG_SYNC_EDGE;
        !           295:        if (fws_cfg.cfg.collector)
        !           296:                ucfg->mode |= CFG_SYNC_COLLECTOR;
        !           297:        ucfg->addrs = 2;
        !           298:        memcpy(ucfg->addr[0].ip6.sin6_addr.s6_addr, &fws_acct.states[0], sizeof(uint64_t));
        !           299:        memcpy(ucfg->addr[0].ip6.sin6_addr.s6_addr + 8, &fws_acct.states[1], sizeof(uint64_t));
        !           300:        memcpy(ucfg->addr[1].ip6.sin6_addr.s6_addr, &fws_acct.aliases[0], sizeof(uint64_t));
        !           301:        memcpy(ucfg->addr[1].ip6.sin6_addr.s6_addr + 8, &fws_acct.aliases[1], sizeof(uint64_t));
        !           302: 
1.1       misho     303:        return 0;
                    304: }
                    305: 
                    306: int
                    307: fwsync_start(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
                    308: {
1.7       misho     309:        int *n;
1.1       misho     310:        ipfw_obj_header *oh;
                    311:        size_t sz;
                    312: 
                    313:        DTRACE();
                    314: 
                    315:        sz = sizeof(*oh) + sizeof(int);
                    316:        /* Check minimum header size */
                    317:        if (sd->valsize < sz)
                    318:                return (EINVAL);
                    319: 
                    320:        oh = (ipfw_obj_header*) sd->kbuf;
                    321: 
                    322:        /* Basic length checks for TLVs */
                    323:        if (oh->ntlv.head.length != sizeof(oh->ntlv))
                    324:                return (EINVAL);
                    325: 
                    326:        n = (int*) (oh + 1);
                    327: 
                    328:        if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
                    329:                fws_cfg.cfg.on |= CFG_SYNC_EDGE;
                    330: 
1.7       misho     331:                callout_reset(&fws_co, hz, fwsync_edge_proc, NULL);
1.8       misho     332: 
1.9       misho     333:                if (!(fws_ctx.config & CTX_EDGE_ONLINE)) {
1.8       misho     334:                        ipfw_register_state_sync(fwsync_state_sync);
1.9       misho     335:                        ipfw_register_alias_sync(fwsync_alias_sync);
                    336:                }
1.8       misho     337: 
                    338:                fws_ctx.config |= CTX_EDGE_ONLINE;
1.1       misho     339:        }
                    340: 
                    341:        if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_READY)) {
                    342:                fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
                    343: 
                    344:                if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
                    345:                        ipfw_register_state_hook(fwsync_state_handler);
                    346:                        ipfw_register_alias_hook(fwsync_alias_handler);
                    347:                }
                    348: 
                    349:                fws_ctx.config |= CTX_COLLECTOR_1_ONLINE;
                    350:        }
                    351: 
                    352:        if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_READY)) {
                    353:                fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
                    354: 
                    355:                if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
                    356:                        ipfw_register_state_hook(fwsync_state_handler);
                    357:                        ipfw_register_alias_hook(fwsync_alias_handler);
                    358:                }
                    359: 
                    360:                fws_ctx.config |= CTX_COLLECTOR_2_ONLINE;
                    361:        }
                    362: 
                    363:        return 0;
                    364: }
                    365: 
                    366: int
                    367: fwsync_stop(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
                    368: {
                    369:        int *n;
                    370:        ipfw_obj_header *oh;
                    371:        size_t sz;
                    372: 
                    373:        DTRACE();
                    374: 
                    375:        sz = sizeof(*oh) + sizeof(int);
                    376:        /* Check minimum header size */
                    377:        if (sd->valsize < sz)
                    378:                return (EINVAL);
                    379: 
                    380:        oh = (ipfw_obj_header*) sd->kbuf;
                    381: 
                    382:        /* Basic length checks for TLVs */
                    383:        if (oh->ntlv.head.length != sizeof(oh->ntlv))
                    384:                return (EINVAL);
                    385: 
                    386:        n = (int*) (oh + 1);
                    387: 
1.7       misho     388:        if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_CFG_EDGE)) {
1.1       misho     389:                fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
1.7       misho     390:                fws_ctx.config &= ~CTX_EDGE_ONLINE;
                    391: 
                    392:                callout_drain(&fws_co);
1.8       misho     393: 
                    394:                ipfw_unregister_state_sync();
1.9       misho     395:                ipfw_unregister_alias_sync();
1.7       misho     396:        }
1.1       misho     397: 
                    398:        if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_ONLINE))
                    399:                fws_ctx.config &= ~CTX_COLLECTOR_2_ONLINE;
                    400:        if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_ONLINE))
                    401:                fws_ctx.config &= ~CTX_COLLECTOR_1_ONLINE;
                    402: 
                    403:        if ((*n & CFG_SYNC_COLLECTOR) && 
                    404:                        !(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
                    405:                fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
                    406: 
                    407:                ipfw_unregister_state_hook();
                    408:                ipfw_unregister_alias_hook();
1.8       misho     409: 
                    410:                taskqueue_drain(fws_tq, &fws_sndpkt_task);
1.1       misho     411:        }
                    412: 
                    413:        return 0;
                    414: }

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