#include #include #include #include #include #include #include #include #include #include #include #include #include static inline int nlmsg_msg_size(int payload) { return NLMSG_HDRLEN + payload; } static inline void *nlmsg_data(const struct nlmsghdr *nlh) { return (unsigned char *) nlh + NLMSG_HDRLEN; } static inline int nlmsg_total_size(int payload) { return NLMSG_ALIGN(nlmsg_msg_size(payload)); } static inline int nlmsg_padlen(int payload) { return nlmsg_total_size(payload) - nlmsg_msg_size(payload); } static struct nlmsghdr *nlmsg_put(void *buf, uint32_t pid, uint32_t seq, int type, int payload, int flags) { struct nlmsghdr *nlh; nlh = (struct nlmsghdr *) buf; nlh->nlmsg_type = type; nlh->nlmsg_len = nlmsg_msg_size(payload); nlh->nlmsg_flags = flags; nlh->nlmsg_pid = pid; nlh->nlmsg_seq = seq; memset((unsigned char *) nlmsg_data(nlh) + payload, 0, nlmsg_padlen(payload)); return nlh; } static int fill_info(unsigned char *buf, uint32_t pid, uint32_t seq, int event, int flags, unsigned proto) { struct rtmsg *r; struct nlmsghdr *nlh; nlh = nlmsg_put(buf, pid, seq, event, sizeof(*r), 0); r = nlmsg_data(nlh); r->rtm_family = AF_INET; r->rtm_dst_len = 32; r->rtm_src_len = 0; r->rtm_tos = 0; r->rtm_table = RT_TABLE_MAIN; r->rtm_type = 0; r->rtm_scope = RT_SCOPE_UNIVERSE; r->rtm_protocol = RTPROT_UNSPEC; r->rtm_flags = flags; return (void *) (r+1) - (void *) buf; } static const char *nltypes[] = { [RTM_NEWROUTE] = "RTM_NEWROUTE", [RTM_DELROUTE] = "RTM_DELROUTE", [RTM_GETROUTE] = "RTM_GETROUTE", [RTM_NEWLINK] = "RTM_NEWLINK", [RTM_DELLINK] = "RTM_DELLINK", [RTM_GETLINK] = "RTM_GETLINK", [RTM_NEWADDR] = "RTM_NEWADDR", [RTM_DELADDR] = "RTM_DELADDR", [RTM_GETADDR] = "RTM_GETADDR", }; static struct sock_filter filter[] = { BPF_STMT(BPF_LD|BPF_ABS|BPF_H, 4), /* 0: ldh [4] */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __constant_htons(RTM_NEWROUTE), 0, 3), /* 1: jeq 0x18 jt 2 jf 5 */ BPF_STMT(BPF_LD|BPF_ABS|BPF_B, 23), /* 2: ldb [23] */ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_ZEBRA, 2, 0), /* 3: jeq 0xb jt 4 jf 5 */ BPF_STMT(BPF_RET|BPF_K, 0), /* 4: ret 0 */ BPF_STMT(BPF_RET|BPF_K, 0xffff), /* 5: ret 0xffff */ }; int main(int ac, char **av) { int i, sk, cc; struct sockaddr_nl snl = { .nl_family = AF_NETLINK, }; socklen_t snl_len = sizeof snl; pid_t pid; unsigned char buf[4096]; struct sock_fprog prog = { .len = sizeof(filter) / sizeof(filter[0]), .filter = filter, }; for (i = 0; i < prog.len; i++ ) printf("%d: %#04x %d %d %#08x\n", i, filter[i].code, filter[i].jt, filter[i].jf, filter[i].k); printf("\n"); fflush(stdout); sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_USERSOCK); if (sk < 0) perror("socket"); if (bind(sk, (struct sockaddr *) &snl, sizeof snl) < 0) perror("bind"); if (getsockname(sk, (struct sockaddr *) &snl, &snl_len) < 0) perror("getsockname"); if (setsockopt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) perror("setsockopt attach filte"); pid = fork(); if (pid == 0) { struct nlmsghdr *nlh; do { struct rtmsg *r; cc = recv(sk, &buf, sizeof buf, 0); if (cc < 0) perror("recv"); for (i = 0; i < 64 && i < cc; i++) printf("%02x%c", buf[i], (i % 16) == 15 ? '\n' : ' '); nlh = (struct nlmsghdr *) buf; printf("\n\tlen=%d type=%s flags=%#x seq=%#x pid=%d\n", nlh->nlmsg_len, nltypes[nlh->nlmsg_type], nlh->nlmsg_flags, nlh->nlmsg_seq, nlh->nlmsg_pid); r = NLMSG_DATA(nlh); printf("\tfamily=%d table=%d proto=%d type=%#x flags=%#x\n\n", r->rtm_family, r->rtm_table, r->rtm_protocol, r->rtm_type, r->rtm_flags); } while (nlh->nlmsg_type != RTM_DELLINK); exit(0); } else { cc = fill_info(buf, 0, 1, RTM_NEWLINK, 0, RTPROT_UNSPEC); if (sendto(sk, buf, cc, 0, (struct sockaddr *) &snl, snl_len) < 0) perror("sendto"); cc = fill_info(buf, 0, 1, RTM_NEWROUTE, RTM_F_CLONED, RTPROT_UNSPEC); if (sendto(sk, buf, cc, 0, (struct sockaddr *) &snl, snl_len) < 0) perror("sendto"); cc = fill_info(buf, 0, 1, RTM_NEWROUTE, 0, RTPROT_ZEBRA); if (sendto(sk, buf, cc, 0, (struct sockaddr *) &snl, snl_len) < 0) perror("sendto"); cc = fill_info(buf, 0, 1, RTM_NEWROUTE, 0, RTPROT_UNSPEC); if (sendto(sk, buf, cc, 0, (struct sockaddr *) &snl, snl_len) < 0) perror("sendto"); cc = fill_info(buf, 0, 1, RTM_DELLINK, 0, RTPROT_UNSPEC); if (sendto(sk, buf, cc, 0, (struct sockaddr *) &snl, snl_len) < 0) perror("sendto"); waitpid(pid, NULL, 0); } return 0; }