Last active
January 8, 2016 07:21
-
-
Save cynron/5f22ca78894d352a9889 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <netinet/in.h> | |
| #include <linux/netlink.h> | |
| #include <linux/rtnetlink.h> | |
| #include <net/if.h> | |
| #include <stdio.h> | |
| #include <stdint.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <assert.h> | |
| uint32_t seq = 0; | |
| #define IPV4_ADDR_LEN 4 | |
| int init_nl_sock() { | |
| /* TODO: error handling */ | |
| struct sockaddr_nl local; | |
| int bufsz =1024 * 1024; | |
| int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
| setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz)); | |
| setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz)); | |
| local.nl_family = AF_NETLINK; | |
| local.nl_groups = RTMGRP_IPV4_ROUTE; | |
| bind(fd, (struct sockaddr*)&local, sizeof(local)); | |
| return fd; | |
| } | |
| int handle(struct nlmsghdr* n) { | |
| fprintf(stderr, "got nlmsghdr seq: %u\n", n->nlmsg_seq); | |
| if (n->nlmsg_type == RTM_NEWROUTE) { | |
| /* it is the answer for our route request */ | |
| if (n->nlmsg_seq == seq) { | |
| struct rtmsg* r = NLMSG_DATA(n); | |
| int len = n->nlmsg_len; | |
| struct rtattr* rta = RTM_RTA(r); | |
| int alen; | |
| char* addr; | |
| int index; | |
| fprintf(stderr, "got answer\n"); | |
| len -= NLMSG_LENGTH(sizeof(*r)); | |
| assert(len >= 0); | |
| while (RTA_OK(rta, len)) { | |
| /* may not have gateway attr */ | |
| if (rta->rta_type == RTA_GATEWAY) { | |
| alen = RTA_PAYLOAD(rta); | |
| /* IPv4, 4 byte */ | |
| assert(alen == IPV4_ADDR_LEN); | |
| addr = RTA_DATA(rta); | |
| fprintf(stderr, "via len: %d, addr: %d.%d.%d.%d\n", alen, addr[0], addr[1], addr[2], addr[3]); | |
| } | |
| if (rta->rta_type == RTA_OIF) { | |
| alen = RTA_PAYLOAD(rta); | |
| /* int */ | |
| assert(alen == sizeof(index)); | |
| index = *(int*)RTA_DATA(rta); | |
| fprintf(stderr, "out device index: %d\n", index); | |
| } | |
| rta = RTA_NEXT(rta, len); | |
| } | |
| assert(len == 0); | |
| } else { | |
| fprintf(stderr, "got route addition broadcast\n"); | |
| } | |
| } | |
| if (n->nlmsg_type == RTM_DELROUTE) { | |
| fprintf(stderr, "got route deletion broadcast\n"); | |
| } | |
| return 0; | |
| } | |
| int r(int fd) { | |
| struct iovec iov; | |
| char buf[8192]; | |
| int status; | |
| struct msghdr msg = { | |
| .msg_name = NULL, | |
| .msg_namelen = 0, | |
| .msg_iov = &iov, | |
| .msg_iovlen = 1 | |
| }; | |
| struct nlmsghdr *n; | |
| iov.iov_base = buf; | |
| iov.iov_len = 8192; | |
| /* TODO: error handling, EINTR, EAGAIN */ | |
| status = recvmsg(fd, &msg, 0); | |
| assert(status > 0); | |
| /* may return multi nlmsgs once recvmsg */ | |
| for (n = (struct nlmsghdr*)buf; status >= sizeof(*n); ) { | |
| int len = n->nlmsg_len; | |
| int l = len - sizeof(*n); | |
| assert(l >= 0 && len <= status); | |
| handle(n); | |
| status -= NLMSG_ALIGN(len); | |
| n = (struct nlmsghdr*)((void*)n + NLMSG_ALIGN(len)); | |
| } | |
| return 0; | |
| } | |
| /* send route request */ | |
| int s(int fd, char* addr) { | |
| struct { | |
| struct nlmsghdr n; | |
| struct rtmsg r; | |
| char attr[1024]; | |
| } req; | |
| struct rtattr* rta; | |
| struct iovec iov; | |
| struct msghdr msg; | |
| struct nlmsghdr* n = &req.n; | |
| struct sockaddr_nl dst_addr; | |
| int len; | |
| req.r.rtm_family = AF_INET; | |
| req.r.rtm_table = 0; | |
| req.r.rtm_protocol = 0; | |
| req.r.rtm_scope = 0; | |
| req.r.rtm_type = 0; | |
| req.r.rtm_src_len = 0; | |
| req.r.rtm_tos = 0; | |
| n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); | |
| n->nlmsg_flags = NLM_F_REQUEST; | |
| n->nlmsg_type = RTM_GETROUTE; | |
| /* | |
| * route request seq id | |
| * used to trace route request | |
| */ | |
| n->nlmsg_seq = ++seq; | |
| rta = (struct rtattr*)((void*)n + NLMSG_ALIGN(n->nlmsg_len)); | |
| len = RTA_LENGTH(IPV4_ADDR_LEN); | |
| rta->rta_type = RTA_DST; | |
| rta->rta_len = len; | |
| memcpy(RTA_DATA(rta), addr, IPV4_ADDR_LEN); | |
| n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); | |
| /* address mask 32 */ | |
| req.r.rtm_dst_len = 32; | |
| iov.iov_base = (void*) n; | |
| iov.iov_len = n->nlmsg_len; | |
| memset(&msg, 0, sizeof(msg)); | |
| msg.msg_name = &dst_addr; | |
| msg.msg_namelen = sizeof(dst_addr); | |
| msg.msg_iov = &iov; | |
| msg.msg_iovlen = 1; | |
| memset(&dst_addr, 0, sizeof(dst_addr)); | |
| dst_addr.nl_family = AF_NETLINK; | |
| /* TODO: error handling */ | |
| return sendmsg(fd, &msg, 0); | |
| } | |
| int main() { | |
| int fd = init_nl_sock(); | |
| /* get route for 7.7.7.7/32 */ | |
| char a[4] = {7, 7, 7, 7}; | |
| s(fd, a); | |
| while (1) { | |
| r(fd); | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment