1 /* rtnl - rtnetlink utility functions 2 * 3 * (C) 2004 by Astaro AG, written by Harald Welte <hwelte (at) astaro.com> 4 * 5 * Adapted to nfnetlink by Eric Leblond <eric (at) inl.fr> 6 * 7 * This software is free software and licensed under GNU GPLv2. 8 * 9 */ 10 11 /* rtnetlink - routing table netlink interface */ 12 13 #include <unistd.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <errno.h> 17 #include <time.h> 18 #include <sys/types.h> 19 #include <sys/uio.h> 20 21 #include <netinet/in.h> 22 23 #include <linux/types.h> 24 #include <sys/socket.h> 25 #include <linux/netlink.h> 26 #include <linux/rtnetlink.h> 27 28 #include "rtnl.h" 29 30 #define rtnl_log(x, ...) 31 32 static inline struct rtnl_handler * 33 find_handler(struct rtnl_handle *rtnl_handle, u_int16_t type) 34 { 35 struct rtnl_handler *h; 36 for (h = rtnl_handle->handlers; h; h = h->next) { 37 if (h->nlmsg_type == type) 38 return h; 39 } 40 return NULL; 41 } 42 43 static int call_handler(struct rtnl_handle *rtnl_handle, 44 u_int16_t type, 45 struct nlmsghdr *hdr) 46 { 47 struct rtnl_handler *h = find_handler(rtnl_handle, type); 48 49 if (!h) { 50 rtnl_log(LOG_DEBUG, "no registered handler for type %u", type); 51 return 0; 52 } 53 54 return (h->handlefn)(hdr, h->arg); 55 } 56 57 /* rtnl_handler_register - register handler for given nlmsg type 58 * @hdlr: handler structure 59 */ 60 int rtnl_handler_register(struct rtnl_handle *rtnl_handle, 61 struct rtnl_handler *hdlr) 62 { 63 rtnl_log(LOG_DEBUG, "registering handler for type %u", 64 hdlr->nlmsg_type); 65 hdlr->next = rtnl_handle->handlers; 66 rtnl_handle->handlers = hdlr; 67 return 1; 68 } 69 70 /* rtnl_handler_unregister - unregister handler for given nlmst type 71 * @hdlr: handler structure 72 */ 73 int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle, 74 struct rtnl_handler *hdlr) 75 { 76 struct rtnl_handler *h, *prev = NULL; 77 78 rtnl_log(LOG_DEBUG, "unregistering handler for type %u", 79 hdlr->nlmsg_type); 80 81 for (h = rtnl_handle->handlers; h; h = h->next) { 82 if (h == hdlr) { 83 if (prev) 84 prev->next = h->next; 85 else 86 rtnl_handle->handlers = h->next; 87 return 1; 88 } 89 prev = h; 90 } 91 return 0; 92 } 93 94 int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 95 { 96 memset(tb, 0, sizeof(struct rtattr *) * max); 97 98 while (RTA_OK(rta, len)) { 99 if (rta->rta_type <= max) 100 tb[rta->rta_type] = rta; 101 rta = RTA_NEXT(rta,len); 102 } 103 if (len) 104 return -1; 105 return 0; 106 } 107 108 /* rtnl_dump_type - ask rtnetlink to dump a specific table 109 * @type: type of table to be dumped 110 */ 111 int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type) 112 { 113 struct { 114 struct nlmsghdr nlh; 115 struct rtgenmsg g; 116 } req; 117 struct sockaddr_nl nladdr; 118 119 memset(&nladdr, 0, sizeof(nladdr)); 120 memset(&req, 0, sizeof(req)); 121 nladdr.nl_family = AF_NETLINK; 122 123 req.nlh.nlmsg_len = sizeof(req); 124 req.nlh.nlmsg_type = type; 125 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; 126 req.nlh.nlmsg_pid = 0; 127 req.nlh.nlmsg_seq = rtnl_handle->rtnl_dump = ++(rtnl_handle->rtnl_seq); 128 req.g.rtgen_family = AF_INET; 129 130 return sendto(rtnl_handle->rtnl_fd, &req, sizeof(req), 0, 131 (struct sockaddr*)&nladdr, sizeof(nladdr)); 132 } 133 134 /* rtnl_receive - receive netlink packets from rtnetlink socket */ 135 int rtnl_receive(struct rtnl_handle *rtnl_handle) 136 { 137 int status; 138 char buf[8192]; 139 struct sockaddr_nl nladdr; 140 struct iovec iov = { buf, sizeof(buf) }; 141 struct nlmsghdr *h; 142 143 struct msghdr msg = { 144 .msg_name = &nladdr, 145 .msg_namelen = sizeof(nladdr), 146 .msg_iov = &iov, 147 .msg_iovlen = 1, 148 }; 149 150 status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0); 151 if (status < 0) { 152 if (errno == EINTR) 153 return 0; 154 rtnl_log(LOG_NOTICE, "OVERRUN on rtnl socket"); 155 return -1; 156 } 157 if (status == 0) { 158 rtnl_log(LOG_ERROR, "EOF on rtnl socket"); 159 return -1; 160 } 161 if (msg.msg_namelen != sizeof(nladdr)) { 162 rtnl_log(LOG_ERROR, "invalid address size"); 163 return -1; 164 } 165 166 h = (struct nlmsghdr *) buf; 167 while (NLMSG_OK(h, status)) { 168 #if 0 169 if (h->nlmsg_pid != rtnl_local.nl_pid || 170 h->nlmsg_seq != rtnl_dump) { 171 goto skip; 172 } 173 #endif 174 175 if (h->nlmsg_type == NLMSG_DONE) { 176 rtnl_log(LOG_NOTICE, "NLMSG_DONE"); 177 return 0; 178 } 179 if (h->nlmsg_type == NLMSG_ERROR) { 180 struct nlmsgerr *err = NLMSG_DATA(h); 181 if (h->nlmsg_len>=NLMSG_LENGTH(sizeof(struct nlmsgerr))) 182 errno = -err->error; 183 rtnl_log(LOG_ERROR, "NLMSG_ERROR, errnp=%d", 184 errno); 185 return -1; 186 } 187 188 if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0) 189 rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u", 190 h->nlmsg_type); 191 h = NLMSG_NEXT(h, status); 192 } 193 return 1; 194 } 195 196 int rtnl_receive_multi(struct rtnl_handle *rtnl_handle) 197 { 198 while (1) { 199 if (rtnl_receive(rtnl_handle) <= 0) 200 break; 201 } 202 return 1; 203 } 204 205 /* rtnl_open - constructor of rtnetlink module */ 206 struct rtnl_handle *rtnl_open(void) 207 { 208 socklen_t addrlen; 209 struct rtnl_handle *h; 210 211 h = calloc(1, sizeof(struct rtnl_handle)); 212 if (!h) 213 return NULL; 214 215 addrlen = sizeof(h->rtnl_local); 216 217 h->rtnl_local.nl_pid = getpid(); 218 h->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 219 if (h->rtnl_fd < 0) { 220 rtnl_log(LOG_ERROR, "unable to create rtnetlink socket"); 221 goto err; 222 } 223 224 memset(&h->rtnl_local, 0, sizeof(h->rtnl_local)); 225 h->rtnl_local.nl_family = AF_NETLINK; 226 h->rtnl_local.nl_groups = RTMGRP_LINK; 227 if (bind(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, addrlen) < 0) { 228 rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket"); 229 goto err_close; 230 } 231 232 if (getsockname(h->rtnl_fd, 233 (struct sockaddr *) &h->rtnl_local, 234 &addrlen) < 0) { 235 rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)"); 236 goto err_close; 237 } 238 239 if (addrlen != sizeof(h->rtnl_local)) { 240 rtnl_log(LOG_ERROR, "invalid address size %u", addr_len); 241 goto err_close; 242 } 243 244 if (h->rtnl_local.nl_family != AF_NETLINK) { 245 rtnl_log(LOG_ERROR, "invalid AF %u", h->rtnl_local.nl_family); 246 goto err_close; 247 } 248 249 h->rtnl_seq = time(NULL); 250 251 return h; 252 253 err_close: 254 close(h->rtnl_fd); 255 err: 256 free(h); 257 return NULL; 258 } 259 260 /* rtnl_close - destructor of rtnetlink module */ 261 void rtnl_close(struct rtnl_handle *rtnl_handle) 262 { 263 close(rtnl_handle->rtnl_fd); 264 free(rtnl_handle); 265 return; 266 } 267