22 #include <linux/if_arp.h> 33 m_hasKernelDump =
false;
34 m_netlinkInitialized =
false;
36 if (!setupNetlink()) {
37 fprintf(stderr,
"Failed to setup netlink\n");
41 fprintf(stderr,
"Failed to initialize cache\n");
47 if (m_netlinkInitialized) {
48 shutdown(m_fd, SHUT_RDWR);
52 if (m_hasKernelDump) {
57 bool Netlink::setupNetlink()
59 if (m_netlinkInitialized) {
63 if ((m_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
64 fprintf(stderr,
"Socket error: %s", strerror(errno));
69 memset(&m_local, 0,
sizeof(m_local));
70 m_local.nl_family = AF_NETLINK;
71 m_local.nl_groups = 0;
73 if (bind(m_fd, (
struct sockaddr *) &m_local,
sizeof(m_local)) < 0) {
74 fprintf(stderr,
"Failed to bind socket: %s \n", strerror(errno));
77 m_pid = m_local.nl_pid;
81 memset(&m_kernel, 0,
sizeof(m_kernel));
82 m_kernel.nl_family = AF_NETLINK;
84 m_netlinkInitialized =
true;
88 template<
typename payload>
89 Netlink::netlink_request<payload> Netlink::createMessage(
const int type,
const int flags)
91 netlink_request<payload> request;
93 request.hdr.nlmsg_len = NLMSG_LENGTH(
sizeof(payload));
94 request.hdr.nlmsg_type = type;
96 request.hdr.nlmsg_flags = flags | NLM_F_ACK | NLM_F_REQUEST;
98 request.hdr.nlmsg_seq = m_sequenceNumber++;
99 request.hdr.nlmsg_pid = m_pid;
101 memset(&request.pay, 0,
sizeof(payload));
102 memset(request.attr, 0,
sizeof(request.attr));
107 template<
typename payload>
108 bool Netlink::addAttribute(netlink_request<payload> &request,
const int type,
const size_t length,
const void *data)
110 long unsigned int MAXSIZE =
sizeof(request.attr);
111 int usedAttributeLength = request.hdr.nlmsg_len -
sizeof(request.hdr) -
sizeof(request.pay);
112 if (usedAttributeLength + RTA_LENGTH(length) > MAXSIZE) {
117 struct rtattr *rta = (
struct rtattr *)(((
char *) &request) + NLMSG_ALIGN(request.hdr.nlmsg_len));
120 rta->rta_type = type;
121 rta->rta_len = RTA_LENGTH(length);
124 memcpy(RTA_DATA(rta), data, length);
127 request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(length);
132 template<
typename payload>
133 bool Netlink::sendMessage(netlink_request<payload> &request)
135 if (!m_netlinkInitialized && !setupNetlink()) {
136 fprintf(stderr,
"Could not setup netlink communication with kernel\n");
143 memset(&io, 0,
sizeof(io));
144 io.iov_base = &request;
145 io.iov_len = request.hdr.nlmsg_len;
148 struct msghdr msghdr;
149 memset(&msghdr, 0,
sizeof(msghdr));
152 msghdr.msg_iov = &io;
153 msghdr.msg_iovlen = 1;
155 msghdr.msg_name = &m_kernel;
156 msghdr.msg_namelen =
sizeof(m_kernel);
158 if ((sendmsg(m_fd, &msghdr, 0)) == -1) {
159 fprintf(stderr,
"Unable to send msg to kernel: %s\n", strerror(errno));
164 int status = readMessage();
166 fprintf(stderr,
"Got an error from the kernel: %s\n", strerror(-status));
168 }
else if (status > 0) {
169 fprintf(stderr,
"Error in the netlink code: %i\n", status);
177 netlink_request<rtmsg> set_gw = createMessage<rtmsg>(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE);
178 set_gw.pay.rtm_family = AF_INET;
179 set_gw.pay.rtm_table = RT_TABLE_MAIN;
180 set_gw.pay.rtm_protocol = RTPROT_STATIC;
181 set_gw.pay.rtm_scope = RT_SCOPE_UNIVERSE;
182 set_gw.pay.rtm_type = RTN_UNICAST;
184 struct in_addr gw_addr;
185 if (inet_aton(gatewayAddress, &gw_addr) == 0) {
188 addAttribute(set_gw, RTA_GATEWAY,
sizeof(gw_addr), &gw_addr);
190 return sendMessage(set_gw);
200 for (LinkInfo link : m_links) {
201 ifinfomsg ifinfo = link.first;
202 if (ifinfo.ifi_index != ifaceIndex) {
207 netlink_request<ifinfomsg> msg_up = createMessage<ifinfomsg>(RTM_NEWLINK, NLM_F_CREATE);
208 msg_up.pay.ifi_family = AF_UNSPEC;
209 msg_up.pay.ifi_flags = ifinfo.ifi_flags | IFF_UP;
210 msg_up.pay.ifi_change |= IFF_UP;
211 msg_up.pay.ifi_index = ifinfo.ifi_index;
212 if (!sendMessage(msg_up)) {
213 fprintf(stderr,
"Failed to bring device %i up\n", ifinfo.ifi_index);
223 bool Netlink::setIP(
const int ifaceIndex,
const in_addr ip,
const unsigned char netmask)
225 for (LinkInfo link : m_links) {
226 ifinfomsg ifinfo = link.first;
227 if (ifinfo.ifi_index != ifaceIndex) {
232 netlink_request<ifaddrmsg> msg_setip = createMessage<ifaddrmsg>(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE);
233 msg_setip.pay.ifa_family = AF_INET;
234 msg_setip.pay.ifa_prefixlen = netmask;
235 msg_setip.pay.ifa_scope = RT_SCOPE_UNIVERSE;
236 msg_setip.pay.ifa_index = ifinfo.ifi_index;
240 in_addr_t inet_netmask = (1 << netmask) -1;
241 in_addr_t inet_bcast = ip.s_addr | (~inet_netmask);
242 in_addr bcast_addr = { inet_bcast };
244 addAttribute(msg_setip, IFA_LOCAL,
sizeof(ip), &ip);
245 addAttribute(msg_setip, IFA_BROADCAST,
sizeof(bcast_addr), &bcast_addr);
248 if (!sendMessage(msg_setip)) {
250 fprintf(stderr,
"Failed to set ip on link %i\n", ifinfo.ifi_index);
263 for (LinkInfo link : m_links) {
264 ifinfomsg ifinfo = link.first;
265 if (ifinfo.ifi_type == ARPHRD_LOOPBACK) {
269 if (ifinfo.ifi_index != ifaceIndex) {
273 netlink_request<ifinfomsg> down_msg = createMessage<ifinfomsg>(RTM_NEWLINK, 0);
274 down_msg.pay.ifi_family = AF_UNSPEC;
275 down_msg.pay.ifi_index = ifinfo.ifi_index;
276 down_msg.pay.ifi_flags = ~IFF_UP;
277 down_msg.pay.ifi_change = IFF_UP;
279 if (!sendMessage(down_msg)) {
295 for (LinkInfo link : m_links) {
296 AttributeList attributes = link.second;
297 for (AttributeInfo attrinfo : attributes) {
298 rtattr attr = attrinfo.first;
299 void *data = attrinfo.second;
301 if (attr.rta_type == IFLA_IFNAME) {
302 char *ifname = (
char *) data;
303 if (strcmp(ifname, ifaceName) == 0) {
320 for (AddressInfo addressInfo : m_addresses) {
321 ifaddrmsg addrmsg = addressInfo.first;
322 if (addrmsg.ifa_index == interfaceIndex) {
323 result.push_back(addressInfo);
332 const int addressFamily,
335 for (AddressInfo addressInfo : haystack) {
336 AttributeList attributes = addressInfo.second;
337 for (AttributeInfo attrPair : attributes) {
340 rtattr attr = attrPair.first;
341 if (attr.rta_type != IFA_ADDRESS && attr.rta_type != IFA_LOCAL) {
345 void *data = attrPair.second;
346 char out[INET6_ADDRSTRLEN];
349 if (inet_ntop(addressFamily, data, out,
sizeof(out)) && strcmp(out, needle) == 0) {
355 std::cout <<
"Netlink does not have address" << std::endl;
359 int Netlink::readMessage()
361 if (!m_netlinkInitialized && !setupNetlink()) {
362 fprintf(stderr,
"Could not setup netlink communication with kernel\n");
366 size_t PAGE_SIZE = getpagesize();
367 char *buf=
new char[PAGE_SIZE];
372 struct nlmsghdr *msg;
374 memset(&reply, 0,
sizeof(reply));
376 struct iovec io = { buf,
sizeof(char) * PAGE_SIZE };
378 reply.msg_iovlen = 1;
379 reply.msg_name = &m_kernel;
380 reply.msg_namelen =
sizeof(m_kernel);
382 len = recvmsg(m_fd, &reply, 0);
387 for (msg = (
struct nlmsghdr *) buf; NLMSG_OK(msg, len); msg = NLMSG_NEXT(msg, len)) {
388 switch(msg->nlmsg_type)
391 struct nlmsgerr *err = (
struct nlmsgerr *)NLMSG_DATA(msg);
392 if (err->error != 0) {
405 saveMessage<ifinfomsg, LinkInfo>(*msg, m_links);
409 saveMessage<ifaddrmsg, AddressInfo>(*msg, m_addresses);
413 saveMessage<rtmsg, RouteInfo>(*msg, m_routes);
433 printf(
"Got dellink\n");
445 printf(
"message type %d, length %d\n", msg->nlmsg_type, msg->nlmsg_len);
460 m_hasKernelDump =
false;
462 netlink_request<rtgenmsg> link_msg = createMessage<rtgenmsg>(RTM_GETLINK, NLM_F_DUMP);
463 link_msg.pay.rtgen_family = AF_PACKET;
464 if (!sendMessage(link_msg)) {
465 std::cerr <<
"Could not send link message" << std::endl;
469 netlink_request<rtgenmsg> addr_msg = createMessage<rtgenmsg>(RTM_GETADDR, NLM_F_DUMP);
470 addr_msg.pay.rtgen_family = AF_PACKET;
471 if (!sendMessage(addr_msg)) {
472 std::cerr <<
"Could not send address message" << std::endl;
476 netlink_request<rtgenmsg> route_msg = createMessage<rtgenmsg>(RTM_GETROUTE, NLM_F_DUMP);
477 route_msg.pay.rtgen_family = AF_PACKET;
478 if (!sendMessage(route_msg)) {
479 std::cerr <<
"Could not send route message" << std::endl;
483 m_hasKernelDump =
true;
490 std::cerr <<
"Could not get cache dump from kernel" << std::endl;
497 template<
typename msgtype>
498 bool Netlink::getAttributes(
const struct nlmsghdr &header, AttributeList &result)
501 char *dataptr = (
char *)NLMSG_DATA(&header);
504 rtattr *attribute = (
struct rtattr *)(dataptr + NLMSG_ALIGN(
sizeof(msgtype)));
507 int len = header.nlmsg_len - NLMSG_LENGTH(
sizeof(msgtype));
508 while (RTA_OK(attribute, len)) {
510 void *data = malloc(RTA_PAYLOAD(attribute));
511 if (data ==
nullptr) {
512 fprintf(stderr,
"Could not malloc enough to store attribute\n");
516 memcpy(data, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
518 std::pair<rtattr, void *> pair(*attribute, data);
519 result.push_back(pair);
522 attribute = RTA_NEXT(attribute, len);
528 template<
typename msgtype,
typename InfoType>
529 bool Netlink::saveMessage(
const struct nlmsghdr &header, std::vector<InfoType> &result)
532 msgtype *msg = (msgtype *) NLMSG_DATA(&header);
534 AttributeList attributes;
535 if (!getAttributes<msgtype>(header, attributes)) {
536 fprintf(stderr,
"Could not get attributes for message\n");
540 result.push_back(std::pair<msgtype, AttributeList>(*msg, attributes));
544 void Netlink::freeAttributes(AttributeList &attrList)
546 for (AttributeInfo attrInfo : attrList) {
547 void *data = attrInfo.second;
552 void Netlink::clearCache()
554 for (LinkInfo link : m_links) {
555 freeAttributes(link.second);
559 for (AddressInfo addr : m_addresses) {
560 freeAttributes(addr.second);
564 for (RouteInfo route : m_routes) {
565 freeAttributes(route.second);
569 m_hasKernelDump =
false;
virtual bool checkKernelDump()
check for a kernel dump, and if not present, try to get one
bool linkDown(const int ifaceIndex)
Bring a given interface down.
bool hasAddress(const std::vector< AddressInfo > &haystack, const int addressFamily, const char *needle)
checks if an address is present in the given list
Netlink()
Construct a new Netlink object.
bool getKernelDump()
get a dump of all links, addresses and routes from the kernel.
bool linkUp(const int ifaceIndex)
Bring the given interface up.
virtual ~Netlink()
release all resources held by the Netlink object
bool findAddresses(const unsigned int interfaceIndex, std::vector< AddressInfo > &result)
Get all addresses associated with the given interface index.
bool setDefaultGateway(const char *gatewayAddress)
Sets an ip address as the default gateway.
bool findLink(const char *ifaceName, LinkInfo &linkInfo)
Check that the device given is a network bridge.
bool setIP(const int ifaceIndex, const in_addr ip, const unsigned char netmask)
Sets an IP address for a network link.
Developers guide to adding a config item: