Add generic netlink infrastructure

This commit is contained in:
Samuel Thibault 2023-04-18 01:07:25 +02:00
parent 60329986b2
commit 5db476bb6e
3 changed files with 86 additions and 4 deletions

View file

@ -38,6 +38,7 @@
#include <libcli.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/genetlink.h>
#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,6 +739,12 @@ static int netlink_handle_ack(struct nlmsghdr *nh, int min_initok_nlseqnum, char
}
else
{
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;
}

View file

@ -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;

1
util.c
View file

@ -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);