diff options
-rw-r--r-- | include/libnfnetlink/linux_nfnetlink.h | 8 | ||||
-rw-r--r-- | src/libnfnetlink.c | 56 |
2 files changed, 45 insertions, 19 deletions
diff --git a/include/libnfnetlink/linux_nfnetlink.h b/include/libnfnetlink/linux_nfnetlink.h index f08e870..934a247 100644 --- a/include/libnfnetlink/linux_nfnetlink.h +++ b/include/libnfnetlink/linux_nfnetlink.h @@ -112,7 +112,6 @@ struct nfnl_callback { int (*call)(struct sock *nl, struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp); - kernel_cap_t cap_required; /* capabilities required for this msg */ u_int16_t attr_count; /* number of nfattr's */ }; @@ -146,7 +145,7 @@ extern void nfnl_unlock(void); extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n); extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n); -extern int nfattr_parse(struct nfattr *tb[], int maxattr, +extern void nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len); #define nfattr_parse_nested(tb, max, nfa) \ @@ -154,11 +153,14 @@ extern int nfattr_parse(struct nfattr *tb[], int maxattr, #define nfattr_bad_size(tb, max, cta_min) \ ({ int __i, __res = 0; \ - for (__i=0; __i<max; __i++) \ + for (__i=0; __i<max; __i++) { \ + if (!cta_min[__i]) \ + continue; \ if (tb[__i] && NFA_PAYLOAD(tb[__i]) < cta_min[__i]){ \ __res = 1; \ break; \ } \ + } \ __res; \ }) diff --git a/src/libnfnetlink.c b/src/libnfnetlink.c index def45fb..5765072 100644 --- a/src/libnfnetlink.c +++ b/src/libnfnetlink.c @@ -33,8 +33,19 @@ #include <sys/types.h> #include <sys/socket.h> +#include <linux/netlink.h> + #include <libnfnetlink/libnfnetlink.h> +#ifndef NETLINK_ADD_MEMBERSHIP +#define NETLINK_ADD_MEMBERSHIP 1 +#endif + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + + #define nfnl_error(format, args...) \ fprintf(stderr, "%s: " format "\n", __FUNCTION__, ## args) @@ -95,25 +106,23 @@ int nfnl_fd(struct nfnl_handle *h) static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh) { - int i; - u_int32_t new_subscriptions = 0; + int i, err; + u_int32_t new_subscriptions = nfnlh->subscriptions; for (i = 0; i < NFNL_MAX_SUBSYS; i++) new_subscriptions |= nfnlh->subsys[i].subscriptions; - if (nfnlh->subscriptions != new_subscriptions) { - int err; - nfnlh->local.nl_groups = new_subscriptions; - err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local, - sizeof(nfnlh->local)); - if (err < 0) { - nfnl_error("bind(netlink): %s", strerror(errno)); - return err; - } - nfnlh->subscriptions = new_subscriptions; + nfnlh->local.nl_groups = new_subscriptions; + err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local, + sizeof(nfnlh->local)); + if (err < 0) { + nfnl_error("bind(netlink): %s", strerror(errno)); + return err; } + nfnlh->subscriptions = new_subscriptions; + return 0; } @@ -156,10 +165,23 @@ struct nfnl_handle *nfnl_open(void) goto err_close; } nfnlh->seq = time(NULL); - /* - * nfnl_talk checks: h->nlmsg_pid != nfnlh->local.nl_pid - */ - nfnlh->local.nl_pid = getpid(); + + /* don't set pid here, only first socket of process has real pid !!! + * binding to pid '0' will default */ + + /* let us do the initial bind */ + if (recalc_rebind_subscriptions(nfnlh) < 0) + goto err_close; + + /* use getsockname to get the netlink pid that the kernel assigned us */ + addr_len = sizeof(nfnlh->local); + err = getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, + &addr_len); + if (addr_len != sizeof(nfnlh->local)) { + nfnl_error("Bad address length (%u != %zd)", addr_len, + sizeof(nfnlh->local)); + goto err_close; + } return nfnlh; @@ -206,6 +228,8 @@ nfnl_subsys_open(struct nfnl_handle *nfnlh, u_int8_t subsys_id, ssh->subscriptions = subscriptions; ssh->subsys_id = subsys_id; + /* FIXME: reimplement this based on + * setsockopt(nfnlh->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,,) */ if (recalc_rebind_subscriptions(nfnlh) < 0) { free(ssh->cb); ssh->cb = NULL; |