c - ipv6 local address using netlink -
i write c code using netlink information ip route table , detect new ip address of gived interface. using ipv4, can filter local address using 'ifa_local'. using ipv6, can't local address. rta_type never equal 'ifa_local' local address.
the used code following:
int main(void) { struct { struct nlmsghdr hdr; struct ifaddrmsg msg; } req; struct sockaddr_nl addr; int sock[2]; memset(&addr, 0, sizeof(addr)); memset(&req, 0, sizeof(req)); if ((sock[0] = socket(pf_netlink, sock_raw, netlink_route)) == -1) { cwmp_log(error,"couldn't open netlink_route socket"); return -1; } addr.nl_family = af_netlink; addr.nl_groups = rtmgrp_ipv6_ifaddr;// |rtmgrp_ipv6_ifaddr; if ((bind(sock[0], (struct sockaddr_in6 *)&addr, sizeof(addr))) == -1) { cwmp_log(error,"couldn't bind netlink socket"); return -1; } netlink_event.fd = sock[0]; if ((sock[1] = socket(pf_netlink, sock_dgram, netlink_route)) == -1) { cwmp_log(error,"couldn't open netlink_route socket"); return -1; } req.hdr.nlmsg_len = nlmsg_length(sizeof(struct ifaddrmsg)); req.hdr.nlmsg_flags = nlm_f_request | nlm_f_root; req.hdr.nlmsg_type = rtm_getaddr; req.msg.ifa_family = af_inet6; if ((send(sock[1], &req, req.hdr.nlmsg_len, 0)) == -1) { cwmp_log(error,"couldn't send netlink socket"); return -1; } struct nlmsghdr *nlh; char buffer[bufsiz]; int msg_size; memset(&buffer, 0, sizeof(buffer)); nlh = (struct nlmsghdr *)buffer; if ((msg_size = recv(sock[1], nlh, bufsiz, 0)) == -1) { cwmp_log(error,"error receiving netlink message"); return; } while (msg_size > sizeof(*nlh)) { int len = nlh->nlmsg_len; int req_len = len - sizeof(*nlh); if (req_len < 0 || len > msg_size) { cwmp_log(error,"error reading netlink message"); return; } if (!nlmsg_ok(nlh, msg_size)) { cwmp_log(error,"netlink message not nlmsg_ok"); return; } if (nlh->nlmsg_type == rtm_newaddr) { printf("new addr \n"); struct ifaddrmsg *ifa = (struct ifaddrmsg *) nlmsg_data(nlh); struct rtattr *rth = ifa_rta(ifa); int rtl = ifa_payload(nlh); char if_name[ifnamsiz], if_addr[inet6_addrstrlen]; char *c; struct in6_addr *in6p; memset(&if_name, 0, sizeof(if_name)); memset(&if_addr, 0, sizeof(if_addr)); while (rtl && rta_ok(rth, rtl)) { printf("rth->rta_type %d \n", rth->rta_type); in6p = (struct in6_addr *)rta_data(rth); printf("addr1: " nip6_fmt "\n",nip6(*in6p)); if (rth->rta_type != ifa_local) { printf("########not ifa_local ############\n"); rth = rta_next(rth, rtl); continue; } printf("======ifa_local======\n"); rth = rta_next(rth, rtl); } } msg_size -= nlmsg_align(len); nlh = (struct nlmsghdr*)((char*)nlh + nlmsg_align(len)); } return 0; }
and trace of execution following: rth->rta_type 6 addr1: 0000:0e0e:0000:1c1e:0031:15c7:0031:15c7
##not ifa_localnew addr rth->rta_type 1 addr1: fd59:ca3e:bd63:0000:0222:07ff:fe41:b9d6
##not ifa_localrth->rta_type 6 addr1: 0000:068c:0000:1ba4:0030:e60b:0030:e60b
##not ifa_localnew addr rth->rta_type 1 addr1: 2001:1338:000a:0000:0000:0000:0000:0196
##not ifa_localrth->rta_type 6 addr1: ffff:ffff:ffff:ffff:0005:a828:0005:a828
##not ifa_localnew addr rth->rta_type 1 addr1: fe80:0000:0000:0000:0222:07ff:fe41:b9d6
##not ifa_localrth->rta_type 6 addr1: ffff:ffff:ffff:ffff:0005:a826:0005:a826
##not ifa_localnew addr rth->rta_type 1 addr1: fe80:0000:0000:0000:0222:07ff:fe41:b9d7
##not ifa_local
try "ifa_address". broadcast interfaces, ifa_local , ifa_address means same. here code snippet kernel if_addr.h.
/* * important comment: * ifa_address prefix address, rather local interface address. * makes no difference configured broadcast interfaces, * point-to-point ifa_address destination address, * local address supplied in ifa_local attribute. */ enum { ifa_unspec, ifa_address, ifa_local, ifa_label, ifa_broadcast, ifa_anycast, ifa_cacheinfo, ifa_multicast, __ifa_max, };
for inet6 rtm_getaddr requests kernel responds ifa_address (addrconf.c:inet6_fill_ifaddr()):-
nla_put(skb, ifa_address, 16, &ifa->addr)
Comments
Post a Comment