summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libnfnetlink/linux_nfnetlink.h8
-rw-r--r--src/libnfnetlink.c56
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;