diff --git a/l2tpns.c b/l2tpns.c index 05986ba..16748db 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "md5.h" #include "dhcp6.h" @@ -64,6 +65,7 @@ uint32_t call_serial_number = 0; // Globals configt *config = NULL; // all configuration int rtnlfd = -1; // route netlink socket +int genlfd = -1; // generic netlink socket int tunfd = -1; // tun interface file handle. (network device) int udpfd[MAX_UDPFD + 1] = INIT_TABUDPFD; // array UDP file handle + 1 for lac udp int udplacfd = -1; // UDP LAC file handle @@ -79,6 +81,7 @@ time_t basetime = 0; // base clock char hostname[MAXHOSTNAME] = ""; // us. static int tunidx; // ifr_ifindex of tun device int rtnlseqnum = 0; // route netlink sequence number +int genlseqnum = 0; // generic netlink sequence number int min_initok_rtnlseqnum = 0; // minimun seq number for messages after init is ok static int syslog_log = 0; // are we logging to syslog FILE *log_stream = 0; // file handle for direct logging (i.e. direct into file, not via syslog). @@ -241,8 +244,12 @@ struct Tringbuffer *ringbuffer = NULL; #endif static ssize_t rtnetlink_send(struct nlmsghdr *nh); -static int netlink_handle_ack(struct nlmsghdr *nh, int min_initok_nlseqnum, char *tun_nl_phase_msg[]); +static ssize_t genetlink_send(struct nlmsghdr *nh); +static ssize_t genetlink_recv(void *buf, ssize_t len); +static int netlink_handle_ack(struct nlmsghdr *nh, int gen, int min_initok_nlseqnum, char *tun_nl_phase_msg[]); static void rtnetlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen); +static void genetlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen); +static int genetlink_getattr(struct nlmsghdr *nh, int type, void *data, int alen); static void cache_ipmap(in_addr_t ip, sessionidt s); static void uncache_ipmap(in_addr_t ip); static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s); @@ -630,6 +637,23 @@ static void initnetlink(void) LOG(0, 0, 0, "Can't bind route netlink socket: %s\n", strerror(errno)); exit(1); } + + genlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + if (genlfd < 0) + { + LOG(0, 0, 0, "Can't create generic netlink socket: %s\n", strerror(errno)); + exit(1); + } + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = getpid(); + + if (bind(genlfd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) + { + LOG(0, 0, 0, "Can't bind generic netlink socket: %s\n", strerror(errno)); + exit(1); + } } // @@ -660,6 +684,13 @@ static ssize_t rtnetlink_send(struct nlmsghdr *nh) return netlink_send(rtnlfd, &rtnlseqnum, nh); } +// +// Send message to the generic netlink socket +static ssize_t genetlink_send(struct nlmsghdr *nh) +{ + return netlink_send(genlfd, &genlseqnum, nh); +} + // // Receive a message from a netlink socket static ssize_t netlink_recv(int fd, void *buf, ssize_t len) @@ -685,9 +716,16 @@ static ssize_t rtnetlink_recv(void *buf, ssize_t len) return netlink_recv(rtnlfd, buf, len); } +// +// Receive a message from the generic netlink socket +static ssize_t genetlink_recv(void *buf, ssize_t len) +{ + return netlink_recv(genlfd, buf, len); +} + // // Look ack netlink message for errors -static int netlink_handle_ack(struct nlmsghdr *nh, int min_initok_nlseqnum, char *tun_nl_phase_msg[]) +static int netlink_handle_ack(struct nlmsghdr *nh, int gen, int min_initok_nlseqnum, char *tun_nl_phase_msg[]) { if (nh->nlmsg_type == NLMSG_ERROR) { @@ -701,7 +739,13 @@ static int netlink_handle_ack(struct nlmsghdr *nh, int min_initok_nlseqnum, char } else { - LOG(0, 0, 0, "For netlink request %d, got a netlink error: %s\n", errmsg->msg.nlmsg_type, strerror(-errmsg->error)); + if (gen) + { + struct genlmsghdr *glh = NLMSG_DATA(&errmsg->msg); + LOG(0, 0, 0, "For generic netlink request %d on %d, got a netlink error: %s\n", glh->cmd, errmsg->msg.nlmsg_type, strerror(-errmsg->error)); + } + else + LOG(0, 0, 0, "For netlink request %d, got a netlink error: %s\n", errmsg->msg.nlmsg_type, strerror(-errmsg->error)); errno = -errmsg->error; return -1; } @@ -732,6 +776,42 @@ static void rtnetlink_addattr(struct nlmsghdr *nh, int type, const void *data, i nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + RTA_ALIGN(len); } +// +// Add an attribute to a message for a generic netlink socket +static void genetlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen) +{ + int len = NLA_HDRLEN + alen; + struct nlattr *nla; + + nla = (struct nlattr *)(((void *)nh) + NLMSG_ALIGN(nh->nlmsg_len)); + nla->nla_type = type; + nla->nla_len = len; + memcpy((char*)nla + NLA_HDRLEN, data, alen); + nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(len); +} + +// +// Find attribute from a message +static int genetlink_getattr(struct nlmsghdr *nh, int type, void *attr, int alen) +{ + char *glh = NLMSG_DATA(nh); + char *data = glh + GENL_HDRLEN; + char *data_end = data + nh->nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN; + struct nlattr *ah; + + for (ah = (void*) data; (char*) ah < data_end; ah = (void*) ((char *) ah + NLA_ALIGN(ah->nla_len))) + { + if ((ah->nla_type & NLA_TYPE_MASK) == type) + { + if (ah->nla_len != NLA_HDRLEN + alen) + LOG(0, 0, 0, "Erroneous attribute %d size\n", type); + memcpy(attr, ((char*) ah + NLA_HDRLEN), alen); + return 0; + } + } + return -1; +} + // messages corresponding to different phases seq number static char *tun_rtnl_phase_msg[] = { "initialized", @@ -4391,7 +4471,7 @@ static void mainloop(void) { struct nlmsghdr *nh = (struct nlmsghdr *)p; s = rtnetlink_recv(p, size_bufp); - netlink_handle_ack(nh, min_initok_rtnlseqnum, tun_rtnl_phase_msg); + netlink_handle_ack(nh, 0, min_initok_rtnlseqnum, tun_rtnl_phase_msg); n--; break; } diff --git a/l2tpns.h b/l2tpns.h index aa0ef46..8b1f121 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1038,6 +1038,7 @@ extern struct Tstats *_statistics; extern in_addr_t my_address; extern int clifd; extern int rtnlfd; +extern int genlfd; extern int epollfd; extern FILE *log_stream; diff --git a/util.c b/util.c index c9bc54e..5c7c44b 100644 --- a/util.c +++ b/util.c @@ -121,6 +121,7 @@ pid_t fork_and_close() #endif /* BGP */ if (rtnlfd != -1) close(rtnlfd); + if (genlfd != -1) close(genlfd); if (pppoediscfd != -1) close(pppoediscfd); if (pppoesessfd != -1) close(pppoesessfd);