root/lib/libipfw3/layer4/ipfw3_layer4.c
/*
 * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
 *
 * This code is derived from software contributed to The DragonFly Project
 * by Bill Yuan <bycn82@dragonflybsd.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of The DragonFly Project nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific, prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <err.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>

#include <net/if.h>
#include <net/route.h>
#include <net/pfil.h>
#include <netinet/in.h>

#include <net/ipfw3/ip_fw3.h>
#include "../../../sbin/ipfw3/ipfw3.h"
#include "ipfw3_layer4.h"

int
char_at(char *str, char c)
{
        int pos;
        for (pos = 0; str[pos] != '\0'; pos++) {
                if (str[pos] == c)
                        return pos;
        }
        return -1;
}

void
parse_tcpflag(ipfw_insn **cmd, int *ac, char **av[])
{
        (*cmd)->opcode = O_LAYER4_TCPFLAG;
        (*cmd)->module = MODULE_LAYER4_ID;
        (*cmd)->len |= LEN_OF_IPFWINSN;
        /* XXX TODO parse the tcpflag value and store in arg1 or arg3 */
        NEXT_ARG1;
}

void
parse_uid(ipfw_insn **cmd, int *ac, char **av[])
{
        char *end;
        uid_t uid;
        struct passwd *pwd;

        NEXT_ARG1;
        ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)(*cmd);
        uid = strtoul(**av, &end, 0);
        pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(**av);
        if (pwd == NULL)
                errx(EX_DATAERR, "uid \"%s\" not exists", **av);

        cmd32->d[0] = pwd->pw_uid;

        (*cmd)->opcode = O_LAYER4_UID;
        (*cmd)->module = MODULE_LAYER4_ID;
        (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32);
        NEXT_ARG1;
}

void
parse_gid(ipfw_insn **cmd, int *ac, char **av[])
{
        char *end;
        gid_t gid;
        struct group *grp;

        NEXT_ARG1;
        ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)(*cmd);
        gid = strtoul(**av, &end, 0);
        grp = (*end == '\0') ? getgrgid(gid) : getgrnam(**av);
        if (grp == NULL)
                errx(EX_DATAERR, "gid \"%s\" not exists", **av);

        cmd32->d[0] = grp->gr_gid;

        (*cmd)->opcode = O_LAYER4_GID;
        (*cmd)->module = MODULE_LAYER4_ID;
        (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32);
        NEXT_ARG1;
}

void
parse_established(ipfw_insn **cmd, int *ac, char **av[])
{
        NEXT_ARG1;
        (*cmd)->opcode = O_LAYER4_ESTABLISHED;
        (*cmd)->module = MODULE_LAYER4_ID;
        (*cmd)->len |= LEN_OF_IPFWINSN;
}

void
parse_bpf(ipfw_insn **cmd, int *ac, char **av[])
{
        struct bpf_program program;
        ipfw_insn_bpf *bpf;
        int avlen;

        NEXT_ARG1;
        (*cmd)->opcode = O_LAYER4_BPF;
        (*cmd)->module = MODULE_LAYER4_ID;

        avlen = strlen(**av);
        if (avlen > 256)
                errx(EX_DATAERR, "bpf \"%s\" too long (max 256)", **av);
        bpf = (ipfw_insn_bpf *)(*cmd);
        strcpy(bpf->bf_str, **av);
        if (pcap_compile_nopcap(65535, DLT_RAW, &program, **av, 1,
                        PCAP_NETMASK_UNKNOWN))
                errx(EX_DATAERR, "bpf \"%s\" compilation error", **av);
        bpf->bf_len = program.bf_len;

        memcpy(&bpf->bf_insn, program.bf_insns,
                        sizeof(struct bpf_insn) * program.bf_len);
        (*cmd)->len |= (sizeof(ipfw_insn_bpf) +
                        sizeof(struct bpf_insn) * (bpf->bf_len - 1)) /
                        sizeof(uint32_t);

        pcap_freecode(&program);
        NEXT_ARG1;
}

void
show_tcpflag(ipfw_insn *cmd, int show_or)
{
        char *word = "tcpflag";
        if (show_or)
                word = "or";
        printf(" %s %d", word, cmd->arg1);
}

void
show_uid(ipfw_insn *cmd, int show_or)
{
        ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
        struct passwd *pwd = getpwuid(cmd32->d[0]);
        char *word = "uid";
        if (show_or)
                word = "or";
        if (pwd){
                printf(" %s %s", word, pwd->pw_name);
        }else{
                printf(" %s %u", word, cmd32->d[0]);
        }
}

void
show_gid(ipfw_insn *cmd, int show_or)
{
        ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
        struct group *grp = getgrgid(cmd32->d[0]);
        char *word = "gid";
        if (show_or)
                word = "or";
        if (grp){
                printf(" %s %s", word, grp->gr_name);
        }else{
                printf(" %s %u", word, cmd32->d[0]);
        }
}

void
show_established(ipfw_insn *cmd, int show_or)
{
        printf(" established");
}

void
show_bpf(ipfw_insn *cmd, int show_or)
{
        ipfw_insn_bpf *bpf;
        char *word = "bpf";
        if (show_or)
                word = "or";
        bpf = (ipfw_insn_bpf *)cmd;
        printf(" %s \"%s\"", word, bpf->bf_str);
}

void
load_module(register_func function, register_keyword keyword)
{
        keyword(MODULE_LAYER4_ID, O_LAYER4_TCPFLAG, "tcpflag", FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_TCPFLAG,
                        (parser_func)parse_tcpflag, (shower_func)show_tcpflag);
        keyword(MODULE_LAYER4_ID, O_LAYER4_UID, "uid", FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_UID,
                        (parser_func)parse_uid, (shower_func)show_uid);
        keyword(MODULE_LAYER4_ID, O_LAYER4_GID, "gid", FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_GID,
                        (parser_func)parse_gid, (shower_func)show_gid);
        keyword(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED, "established", FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
                        (parser_func)parse_established, (shower_func)show_established);
        keyword(MODULE_LAYER4_ID, O_LAYER4_BPF, "bpf", FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_BPF,
                        (parser_func)parse_bpf, (shower_func)show_bpf);
}