From efcfbadb265ced5289f64c76bff777f20565a13e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 24 Apr 2013 01:03:33 +0200 Subject: examples: rtnl-route-add improvements (including IPv6 support) Now, both IPv4 and IPv6 are supported simultaneously in one single file. While at it: * I moved the declarations to the beginning of the main function. * Renamed mask by prefix, which seems more appropriate to me. * Use RTPROTO_STATIC, as the route has been added by the administrator. * Set NLM_F_ACK, so we get a report from the kernel about our query and treat reply from the kernel. * Stricter argc checking. * Use perror instead of printf for error reporting. Signed-off-by: Pablo Neira Ayuso --- examples/rtnl/rtnl-route-add.c | 81 +++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/examples/rtnl/rtnl-route-add.c b/examples/rtnl/rtnl-route-add.c index 6d166da..dd810c9 100644 --- a/examples/rtnl/rtnl-route-add.c +++ b/examples/rtnl/rtnl-route-add.c @@ -14,63 +14,83 @@ int main(int argc, char *argv[]) { + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct rtmsg *rtm; + uint32_t prefix, seq, portid; + union { + in_addr_t ip; + struct in6_addr ip6; + } dst; + union { + in_addr_t ip; + struct in6_addr ip6; + } gw; + int iface, ret, family = AF_INET; + if (argc <= 3) { printf("Usage: %s iface destination cidr [gateway]\n", argv[0]); printf("Example: %s eth0 10.0.1.12 32 10.0.1.11\n", argv[0]); + printf(" %s eth0 ffff::10.0.1.12 128 fdff::1\n", argv[0]); exit(EXIT_FAILURE); } - int iface; iface = if_nametoindex(argv[1]); if (iface == 0) { - printf("Bad interface name\n"); + perror("if_nametoindex"); exit(EXIT_FAILURE); } - in_addr_t dst; if (!inet_pton(AF_INET, argv[2], &dst)) { - printf("Bad destination\n"); - exit(EXIT_FAILURE); + if (!inet_pton(AF_INET6, argv[2], &dst)) { + perror("inet_pton"); + exit(EXIT_FAILURE); + } + family = AF_INET6; } - uint32_t mask; - if (sscanf(argv[3], "%u", &mask) == 0) { - printf("Bad CIDR\n"); + if (sscanf(argv[3], "%u", &prefix) == 0) { + perror("sscanf"); exit(EXIT_FAILURE); } - in_addr_t gw; - if (argc >= 5 && !inet_pton(AF_INET, argv[4], &gw)) { - printf("Bad gateway\n"); + if (argc == 5 && !inet_pton(family, argv[4], &gw)) { + perror("inet_pton"); exit(EXIT_FAILURE); } - struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - struct rtmsg *rtm; - nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = RTM_NEWROUTE; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; - nlh->nlmsg_seq = time(NULL); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg)); - rtm->rtm_family = AF_INET; - rtm->rtm_dst_len = mask; + rtm->rtm_family = family; + rtm->rtm_dst_len = prefix; rtm->rtm_src_len = 0; rtm->rtm_tos = 0; - rtm->rtm_protocol = RTPROT_BOOT; + rtm->rtm_protocol = RTPROT_STATIC; rtm->rtm_table = RT_TABLE_MAIN; rtm->rtm_type = RTN_UNICAST; /* is there any gateway? */ rtm->rtm_scope = (argc == 4) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; rtm->rtm_flags = 0; - mnl_attr_put_u32(nlh, RTA_DST, dst); + if (family == AF_INET) + mnl_attr_put_u32(nlh, RTA_DST, dst.ip); + else + mnl_attr_put(nlh, RTA_DST, sizeof(struct in6_addr), &dst); + mnl_attr_put_u32(nlh, RTA_OIF, iface); - if (argc >= 5) - mnl_attr_put_u32(nlh, RTA_GATEWAY, gw); + if (argc == 5) { + if (family == AF_INET) + mnl_attr_put_u32(nlh, RTA_GATEWAY, gw.ip); + else { + mnl_attr_put(nlh, RTA_DST, sizeof(struct in6_addr), + &gw.ip6); + } + } nl = mnl_socket_open(NETLINK_ROUTE); if (nl == NULL) { @@ -82,12 +102,25 @@ int main(int argc, char *argv[]) perror("mnl_socket_bind"); exit(EXIT_FAILURE); } + portid = mnl_socket_get_portid(nl); if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { perror("mnl_socket_send"); exit(EXIT_FAILURE); } + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret < 0) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret < 0) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + mnl_socket_close(nl); return 0; -- cgit v1.2.3