From 0506a5ed4e56863627c54aedad30ad61221292ef Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 19 Mar 2020 21:56:45 +0000 Subject: [PATCH] Handle old kernels that don't do NETLINK_NO_ENOBUFS. Deal with both old kernel header files that don't define it, and old kernels that don't implement it. Also generalise Linux kernel version handling. --- src/dnsmasq.c | 6 +++++- src/dnsmasq.h | 6 +++++- src/ipset.c | 17 +---------------- src/netlink.c | 8 ++++++-- src/util.c | 23 +++++++++++++++++++++++ 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 286a1cd..74938ff 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -89,11 +89,15 @@ int main (int argc, char **argv) sigaction(SIGPIPE, &sigact, NULL); umask(022); /* known umask, create leases and pid files as 0644 */ - + rand_init(); /* Must precede read_opts() */ read_opts(argc, argv, compile_opts); +#ifdef HAVE_LINUX_NETWORK + daemon->kernel_version = kernel_version(); +#endif + if (daemon->edns_pktsz < PACKETSZ) daemon->edns_pktsz = PACKETSZ; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 7349332..f747868 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -141,6 +141,7 @@ typedef unsigned long long u64; #endif #if defined(HAVE_LINUX_NETWORK) +#include #include #include /* There doesn't seem to be a universally-available @@ -1108,7 +1109,7 @@ extern struct daemon { int inotifyfd; #endif #if defined(HAVE_LINUX_NETWORK) - int netlinkfd; + int netlinkfd, kernel_version; #elif defined(HAVE_BSD_NETWORK) int dhcp_raw_fd, dhcp_icmp_fd, routefd; #endif @@ -1288,6 +1289,9 @@ int read_write(int fd, unsigned char *packet, int size, int rw); void close_fds(long max_fd, int spare1, int spare2, int spare3); int wildcard_match(const char* wildcard, const char* match); int wildcard_matchn(const char* wildcard, const char* match, int num); +#ifdef HAVE_LINUX_NETWORK +int kernel_version(void); +#endif /* log.c */ void die(char *message, char *arg1, int exit_code) ATTRIBUTE_NORETURN; diff --git a/src/ipset.c b/src/ipset.c index 7b97ea8..0c014cb 100644 --- a/src/ipset.c +++ b/src/ipset.c @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include /* We want to be able to compile against old header files @@ -87,20 +85,7 @@ static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, con void ipset_init(void) { - struct utsname utsname; - int version; - char *split; - - if (uname(&utsname) < 0) - die(_("failed to find kernel version: %s"), NULL, EC_MISC); - - split = strtok(utsname.release, "."); - version = (split ? atoi(split) : 0); - split = strtok(NULL, "."); - version = version * 256 + (split ? atoi(split) : 0); - split = strtok(NULL, "."); - version = version * 256 + (split ? atoi(split) : 0); - old_kernel = (version < KERNEL_VERSION(2,6,32)); + old_kernel = (daemon->kernel_version < KERNEL_VERSION(2,6,32)); if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1) return; diff --git a/src/netlink.c b/src/netlink.c index a1ca5d1..3af54c4 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -27,6 +27,9 @@ #define SOL_NETLINK 270 #endif +#ifndef NETLINK_NO_ENOBUFS +#define NETLINK_NO_ENOBUFS 5 +#endif /* linux 2.6.19 buggers up the headers, patch it up here. */ #ifndef IFA_RTA @@ -79,10 +82,11 @@ void netlink_init(void) } if (daemon->netlinkfd == -1 || - setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1 || + (daemon->kernel_version >= KERNEL_VERSION(2,6,30) && + setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1) || getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1) die(_("cannot create netlink socket: %s"), NULL, EC_MISC); - + /* save pid assigned by bind() and retrieved by getsockname() */ netlink_pid = addr.nl_pid; diff --git a/src/util.c b/src/util.c index 0b0c7de..5f13027 100644 --- a/src/util.c +++ b/src/util.c @@ -30,6 +30,10 @@ #include #endif +#ifdef HAVE_LINUX_NETWORK +#include +#endif + /* SURF random number generator */ static u32 seed[32]; @@ -782,3 +786,22 @@ int wildcard_matchn(const char* wildcard, const char* match, int num) return (!num) || (*wildcard == *match); } + +#ifdef HAVE_LINUX_NETWORK +int kernel_version(void) +{ + struct utsname utsname; + int version; + char *split; + + if (uname(&utsname) < 0) + die(_("failed to find kernel version: %s"), NULL, EC_MISC); + + split = strtok(utsname.release, "."); + version = (split ? atoi(split) : 0); + split = strtok(NULL, "."); + version = version * 256 + (split ? atoi(split) : 0); + split = strtok(NULL, "."); + return version * 256 + (split ? atoi(split) : 0); +} +#endif