Thanks you for this review, I am going to send a v3 iteration with the changes 
done and tested.

El 14 de agosto de 2018 16:10:33 CEST, Pablo Neira Ayuso <pa...@netfilter.org> 
escribió:
>On Mon, Aug 13, 2018 at 06:57:08PM +0200, Fernando Fernandez Mancera
>wrote:
>[...]
>> diff --git a/include/nfnl_osf.h b/include/nfnl_osf.h
>> new file mode 100644
>> index 0000000..b676045
>> --- /dev/null
>> +++ b/include/nfnl_osf.h
>
>No need for a new nfnl_osf.h file, please use the existing
>include/osf.h.
>
>> @@ -0,0 +1,10 @@
>> +#ifndef _NFNL_OSF_H
>> +#define _NFNL_OSF_H
>> +
>> +#define OS_SIGNATURES DEFAULT_INCLUDE_PATH "/pf.os"
>> +
>> +bool osf_init;
>
>This needs to be:
>
>        extern bool osf_init;
>
>Then, define 'bool osf_init' from the nfnl_osf.c file.
>
>Make sure you update include/Makefile.am so `make distcheck' doesn't
>break.
>
>> +
>> +int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del);
>> +
>> +#endif      /* _NFNL_OSF_H */
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index ed3640e..e569029 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -57,6 +57,7 @@ libnftables_la_SOURCES =                   \
>>              services.c                      \
>>              mergesort.c                     \
>>              osf.c                           \
>> +            nfnl_osf.c                      \
>>              tcpopt.c                        \
>>              socket.c                        \
>>              libnftables.c
>> diff --git a/src/nfnl_osf.c b/src/nfnl_osf.c
>> new file mode 100644
>> index 0000000..53e4ec6
>> --- /dev/null
>> +++ b/src/nfnl_osf.c
>> @@ -0,0 +1,424 @@
>> +/*
>> + * Copyright (c) 2005 Evgeniy Polyakov <john...@2ka.mxt.ru>
>> + *
>> + *
>> + * This program is free software; you can redistribute it and/or
>modify
>> + * it under the terms of the GNU General Public License as published
>by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
>02110-1301, USA.
>> + */
>> +
>> +#include <sys/time.h>
>> +
>> +#include <ctype.h>
>> +#include <errno.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <time.h>
>> +
>> +#include <netinet/ip.h>
>> +#include <netinet/tcp.h>
>> +
>> +#include <linux/unistd.h>
>> +
>> +#include <libmnl/libmnl.h>
>> +
>> +#include <linux/netfilter/nfnetlink.h>
>> +#include <linux/netfilter/nfnetlink_osf.h>
>> +#include <mnl.h>
>> +#include <nfnl_osf.h>
>> +
>> +#define OPTDEL                      ','
>> +#define OSFPDEL             ':'
>> +#define MAXOPTSTRLEN                128
>> +
>> +static struct nf_osf_opt IANA_opts[] = {
>> +    { .kind = 0, .length = 1,},
>> +    { .kind=1, .length=1,},
>> +    { .kind=2, .length=4,},
>> +    { .kind=3, .length=3,},
>> +    { .kind=4, .length=2,},
>> +    { .kind=5, .length=1,},         /* SACK length is not defined */
>> +    { .kind=6, .length=6,},
>> +    { .kind=7, .length=6,},
>> +    { .kind=8, .length=10,},
>> +    { .kind=9, .length=2,},
>> +    { .kind=10, .length=3,},
>> +    { .kind=11, .length=1,},                /* CC: Suppose 1 */
>> +    { .kind=12, .length=1,},                /* the same */
>> +    { .kind=13, .length=1,},                /* and here too */
>> +    { .kind=14, .length=3,},
>> +    { .kind=15, .length=1,},                /* TCP Alternate Checksum Data. 
>> Length is
>not defined */
>> +    { .kind=16, .length=1,},
>> +    { .kind=17, .length=1,},
>> +    { .kind=18, .length=3,},
>> +    { .kind=19, .length=18,},
>> +    { .kind=20, .length=1,},
>> +    { .kind=21, .length=1,},
>> +    { .kind=22, .length=1,},
>> +    { .kind=23, .length=1,},
>> +    { .kind=24, .length=1,},
>> +    { .kind=25, .length=1,},
>> +    { .kind=26, .length=1,},
>> +};
>> +
>> +static void uloga(const char *f, struct netlink_ctx *ctx, ...)
>> +{
>> +    if (!(ctx->debug_mask & NFT_DEBUG_NETLINK))
>> +            return;
>> +
>> +    nft_print(ctx->octx, "%s", f);
>> +}
>> +
>> +static char *nf_osf_strchr(char *ptr, char c)
>> +{
>> +    char *tmp;
>> +
>> +    tmp = strchr(ptr, c);
>> +    if (tmp)
>> +            *tmp = '\0';
>> +
>> +    while (tmp && tmp + 1 && isspace(*(tmp + 1)))
>> +            tmp++;
>> +
>> +    return tmp;
>> +}
>> +
>> +static void nf_osf_parse_opt(struct nf_osf_opt *opt, __u16 *optnum,
>char *obuf, int olen)
>> +{
>> +    int i, op;
>> +    char *ptr, wc;
>> +    unsigned long val;
>> +
>> +    ptr = &obuf[0];
>> +    i = 0;
>> +    while (ptr != NULL && i < olen && *ptr != 0) {
>> +            val = 0;
>> +            op = 0;
>> +            wc = OSF_WSS_PLAIN;
>> +            switch (obuf[i]) {
>> +            case 'N':
>> +                    op = OSFOPT_NOP;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            *ptr = '\0';
>> +                            ptr++;
>> +                            i += (int)(ptr - &obuf[i]);
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            case 'S':
>> +                    op = OSFOPT_SACKP;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            *ptr = '\0';
>> +                            ptr++;
>> +                            i += (int)(ptr - &obuf[i]);
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            case 'T':
>> +                    op = OSFOPT_TS;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            *ptr = '\0';
>> +                            ptr++;
>> +                            i += (int)(ptr - &obuf[i]);
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            case 'W':
>> +                    op = OSFOPT_WSO;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            switch (obuf[i + 1]) {
>> +                            case '%':
>> +                                    wc = OSF_WSS_MODULO;
>> +                                    break;
>> +                            case 'S':
>> +                                    wc = OSF_WSS_MSS;
>> +                                    break;
>> +                            case 'T':
>> +                                    wc = OSF_WSS_MTU;
>> +                                    break;
>> +                            default:
>> +                                    wc = OSF_WSS_PLAIN;
>> +                                    break;
>> +                            }
>> +
>> +                            *ptr = '\0';
>> +                            ptr++;
>> +                            if (wc)
>> +                                    val = strtoul(&obuf[i + 2], NULL, 10);
>> +                            else
>> +                                    val = strtoul(&obuf[i + 1], NULL, 10);
>> +                            i += (int)(ptr - &obuf[i]);
>> +
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            case 'M':
>> +                    op = OSFOPT_MSS;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            if (obuf[i + 1] == '%')
>> +                                    wc = OSF_WSS_MODULO;
>> +                            *ptr = '\0';
>> +                            ptr++;
>> +                            if (wc)
>> +                                    val = strtoul(&obuf[i + 2], NULL, 10);
>> +                            else
>> +                                    val = strtoul(&obuf[i + 1], NULL, 10);
>> +                            i += (int)(ptr - &obuf[i]);
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            case 'E':
>> +                    op = OSFOPT_EOL;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            *ptr = '\0';
>> +                            ptr++;
>> +                            i += (int)(ptr - &obuf[i]);
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            default:
>> +                    op = OSFOPT_EMPTY;
>> +                    ptr = nf_osf_strchr(&obuf[i], OPTDEL);
>> +                    if (ptr) {
>> +                            ptr++;
>> +                            i += (int)(ptr - &obuf[i]);
>> +                    } else
>> +                            i++;
>> +                    break;
>> +            }
>> +
>> +            if (op != OSFOPT_EMPTY) {
>> +                    opt[*optnum].kind = IANA_opts[op].kind;
>> +                    opt[*optnum].length = IANA_opts[op].length;
>> +                    opt[*optnum].wc.wc = wc;
>> +                    opt[*optnum].wc.val = val;
>> +                    (*optnum)++;
>> +            }
>> +    }
>> +}
>> +
>> +static int osf_load_line(char *buffer, int len, int del, struct
>mnl_socket *nl,
>> +                     struct netlink_ctx *ctx)
>> +{
>> +    int i, cnt = 0;
>> +    char obuf[MAXOPTSTRLEN];
>> +    struct nf_osf_user_finger f;
>> +    char *pbeg, *pend;
>> +    struct nlmsghdr *nlh;
>> +    struct nfgenmsg *nfg;
>> +    char buf[MNL_SOCKET_BUFFER_SIZE];
>> +
>> +    memset(&f, 0, sizeof(struct nf_osf_user_finger));
>> +
>> +    uloga("Loading '%s'.\n", ctx, buffer);
>> +
>> +    for (i = 0; i < len && buffer[i] != '\0'; ++i) {
>> +            if (buffer[i] == ':')
>> +                    cnt++;
>> +    }
>> +
>> +    if (cnt != 8) {
>> +            uloga("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be
>%d.\n", ctx, buffer, cnt, i, len);
>> +            return -EINVAL;
>> +    }
>> +
>> +    memset(obuf, 0, sizeof(obuf));
>> +
>> +    pbeg = buffer;
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            if (pbeg[0] == 'S') {
>> +                    f.wss.wc = OSF_WSS_MSS;
>> +                    if (pbeg[1] == '%')
>> +                            f.wss.val = strtoul(&pbeg[2], NULL, 10);
>> +                    else if (pbeg[1] == '*')
>> +                            f.wss.val = 0;
>> +                    else
>> +                            f.wss.val = strtoul(&pbeg[1], NULL, 10);
>> +            } else if (pbeg[0] == 'T') {
>> +                    f.wss.wc = OSF_WSS_MTU;
>> +                    if (pbeg[1] == '%')
>> +                            f.wss.val = strtoul(&pbeg[2], NULL, 10);
>> +                    else if (pbeg[1] == '*')
>> +                            f.wss.val = 0;
>> +                    else
>> +                            f.wss.val = strtoul(&pbeg[1], NULL, 10);
>> +            } else if (pbeg[0] == '%') {
>> +                    f.wss.wc = OSF_WSS_MODULO;
>> +                    f.wss.val = strtoul(&pbeg[1], NULL, 10);
>> +            } else if (isdigit(pbeg[0])) {
>> +                    f.wss.wc = OSF_WSS_PLAIN;
>> +                    f.wss.val = strtoul(&pbeg[0], NULL, 10);
>> +            }
>> +
>> +            pbeg = pend + 1;
>> +    }
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            f.ttl = strtoul(pbeg, NULL, 10);
>> +            pbeg = pend + 1;
>> +    }
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            f.df = strtoul(pbeg, NULL, 10);
>> +            pbeg = pend + 1;
>> +    }
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            f.ss = strtoul(pbeg, NULL, 10);
>> +            pbeg = pend + 1;
>> +    }
>> +
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            cnt = snprintf(obuf, sizeof(obuf), "%s,", pbeg);
>> +            pbeg = pend + 1;
>> +    }
>> +
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            if (pbeg[0] == '@' || pbeg[0] == '*')
>> +                    cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 
>> 1);
>> +            else
>> +                    cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg);
>> +            pbeg = pend + 1;
>> +    }
>> +
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            cnt = snprintf(f.version, sizeof(f.version), "%s", pbeg);
>> +            pbeg = pend + 1;
>> +    }
>> +
>> +    pend = nf_osf_strchr(pbeg, OSFPDEL);
>> +    if (pend) {
>> +            *pend = '\0';
>> +            cnt =
>> +                snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg);
>> +            pbeg = pend + 1;
>> +    }
>> +
>> +    nf_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));
>> +
>> +    memset(buf, 0, sizeof(buf));
>> +
>> +    if (del) {
>> +            nlh = nftnl_nlmsg_build_hdr(buf, (NFNL_SUBSYS_OSF << 8) |
>> +                                        OSF_MSG_REMOVE, AF_UNSPEC,
>> +                                        NLM_F_REQUEST | NLM_F_ACK,
>> +                                        ctx->seqnum);
>> +
>> +            nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
>> +            nfg->nfgen_family = AF_UNSPEC;
>> +            nfg->version = NFNETLINK_V0;
>> +            nfg->res_id = 0;
>> +    } else {
>> +            nlh = nftnl_nlmsg_build_hdr(buf, (NFNL_SUBSYS_OSF << 8) |
>> +                                        OSF_MSG_ADD, AF_UNSPEC,
>> +                                        NLM_F_REQUEST | NLM_F_CREATE |
>> +                                        NLM_F_ACK, ctx->seqnum);
>> +
>> +            nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
>> +            nfg->nfgen_family = AF_UNSPEC;
>> +            nfg->version = NFNETLINK_V0;
>> +            nfg->res_id = 0;
>> +
>> +            mnl_attr_put(nlh, OSF_ATTR_FINGER, sizeof(struct
>nf_osf_user_finger), &f);
>> +    }
>> +
>> +    return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, 0, NULL);
>> +}
>> +
>> +static int osf_load_entries(int del, struct mnl_socket *nl,
>> +                        struct netlink_ctx *ctx)
>> +{
>> +    FILE *inf;
>> +    int err = 0;
>> +    char buf[1024];
>> +
>> +    inf = fopen(OS_SIGNATURES, "r");
>> +    if (!inf) {
>> +            uloga("Failed to open file '%s'", ctx, OS_SIGNATURES);
>> +            return -1;
>> +    }
>> +
>> +    while(fgets(buf, sizeof(buf), inf)) {
>> +            int len;
>> +
>> +            if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
>> +                    continue;
>> +
>> +            len = strlen(buf) - 1;
>> +
>> +            if (len <= 0)
>> +                    continue;
>> +
>> +            buf[len] = '\0';
>> +
>> +            err = osf_load_line(buf, len, del, nl, ctx);
>> +            if (err)
>> +                    break;
>> +
>> +            memset(buf, 0, sizeof(buf));
>> +    }
>> +
>> +    fclose(inf);
>> +    return err;
>> +}
>> +
>> +int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del)
>> +{
>> +    int err;
>> +    struct mnl_socket *nl;
>> +
>> +    nl = mnl_socket_open(NETLINK_NETFILTER);
>> +    if (nl == NULL) {
>> +            err = -EINVAL;
>> +            uloga("Failed to open mnl socket", ctx);
>> +            goto err_out_exit;
>> +    }
>> +
>> +    if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
>> +            err = -EINVAL;
>> +            uloga("Failed to bind mnl socket", ctx);
>> +            goto err_out_exit;
>> +    }
>> +
>> +#ifndef NFNL_SUBSYS_OSF
>> +#define NFNL_SUBSYS_OSF     5
>> +#endif
>
>Remove this #ifdef, not needed. NFNL_SUBSYS_OSF is already defined in
>nfnetlink_osf.h
>
>> +    err = osf_load_entries(del, nl, ctx);
>> +    if (err < 0)
>> +            goto err_out_close;
>> +
>> +    return 0;
>> +
>> +err_out_close:
>> +    mnl_socket_close(nl);
>> +err_out_exit:
>> +    return err;
>> +}
>> diff --git a/src/osf.c b/src/osf.c
>> index 131d54e..210bfbe 100644
>> --- a/src/osf.c
>> +++ b/src/osf.c
>> @@ -3,6 +3,7 @@
>>  #include <utils.h>
>>  #include <string.h>
>>  #include <osf.h>
>> +#include <nfnl_osf.h>
>>  
>>  static void osf_expr_print(const struct expr *expr, struct
>output_ctx *octx)
>>  {
>> @@ -26,6 +27,7 @@ struct expr *osf_expr_alloc(const struct location
>*loc)
>>      const struct datatype *type = &string_type;
>>      struct expr *expr;
>>  
>> +    osf_init = true;
>>      expr = expr_alloc(loc, &osf_expr_ops, type,
>>                        BYTEORDER_HOST_ENDIAN, len);
>>  
>> diff --git a/src/rule.c b/src/rule.c
>> index 7a7ac73..7421ffc 100644
>> --- a/src/rule.c
>> +++ b/src/rule.c
>> @@ -22,6 +22,7 @@
>>  #include <netdb.h>
>>  #include <netlink.h>
>>  #include <json.h>
>> +#include <nfnl_osf.h>
>>  
>>  #include <libnftnl/common.h>
>>  #include <libnftnl/ruleset.h>
>> @@ -2135,6 +2136,9 @@ int do_command(struct netlink_ctx *ctx, struct
>cmd *cmd)
>>      default:
>>              BUG("invalid command object type %u\n", cmd->obj);
>>      }
>> +
>> +    if (osf_init)
>> +            nfnl_osf_load_fingerprints(ctx, 0);
>
>You have to update do_command() to replace all:
>
>        case blah:
>                return ...;
>
>to
>        case blah:
>                err = ...;
>                break;
>
>Otherwise this code is never exercised.
>
>When testing this, make sure nfnl_osf_load_fingerprints() is called.
>
>You can use:
>
>        nft --debug=netlink add rule x y osf name "linux"
>
>to see if you trigger uloga() calls for debugging so you make sure you
>properly test your patches.
>
>Thanks.

Reply via email to