1 /* 2 * iptoken.c "ip token" 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Daniel Borkmann, <borkmann (at) redhat.com> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <stdbool.h> 15 #include <unistd.h> 16 #include <syslog.h> 17 #include <fcntl.h> 18 #include <string.h> 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 #include <netinet/ip.h> 22 #include <arpa/inet.h> 23 #include <linux/types.h> 24 #include <linux/if.h> 25 26 #include "rt_names.h" 27 #include "utils.h" 28 #include "ip_common.h" 29 30 extern struct rtnl_handle rth; 31 32 struct rtnl_dump_args { 33 FILE *fp; 34 int ifindex; 35 }; 36 37 static void usage(void) __attribute__((noreturn)); 38 39 static void usage(void) 40 { 41 fprintf(stderr, "Usage: ip token [ list | set | get ] [ TOKEN ] [ dev DEV ]\n"); 42 exit(-1); 43 } 44 45 static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 46 { 47 struct rtnl_dump_args *args = arg; 48 FILE *fp = args->fp; 49 int ifindex = args->ifindex; 50 struct ifinfomsg *ifi = NLMSG_DATA(n); 51 int len = n->nlmsg_len; 52 struct rtattr *tb[IFLA_MAX + 1]; 53 struct rtattr *ltb[IFLA_INET6_MAX + 1]; 54 char abuf[256]; 55 56 if (n->nlmsg_type != RTM_NEWLINK) 57 return -1; 58 59 len -= NLMSG_LENGTH(sizeof(*ifi)); 60 if (len < 0) 61 return -1; 62 63 if (ifi->ifi_family != AF_INET6) 64 return -1; 65 if (ifi->ifi_index == 0) 66 return -1; 67 if (ifindex > 0 && ifi->ifi_index != ifindex) 68 return 0; 69 if (ifi->ifi_flags & (IFF_LOOPBACK | IFF_NOARP)) 70 return 0; 71 72 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); 73 if (!tb[IFLA_PROTINFO]) 74 return -1; 75 76 parse_rtattr_nested(ltb, IFLA_INET6_MAX, tb[IFLA_PROTINFO]); 77 if (!ltb[IFLA_INET6_TOKEN]) { 78 fprintf(stderr, "Seems there's no support for IPv6 token!\n"); 79 return -1; 80 } 81 82 fprintf(fp, "token %s ", 83 format_host(ifi->ifi_family, 84 RTA_PAYLOAD(ltb[IFLA_INET6_TOKEN]), 85 RTA_DATA(ltb[IFLA_INET6_TOKEN]), 86 abuf, sizeof(abuf))); 87 fprintf(fp, "dev %s ", ll_index_to_name(ifi->ifi_index)); 88 fprintf(fp, "\n"); 89 fflush(fp); 90 91 return 0; 92 } 93 94 static int iptoken_list(int argc, char **argv) 95 { 96 int af = AF_INET6; 97 struct rtnl_dump_args da; 98 99 memset(&da, 0, sizeof(da)); 100 da.fp = stdout; 101 102 while (argc > 0) { 103 if (strcmp(*argv, "dev") == 0) { 104 NEXT_ARG(); 105 if ((da.ifindex = ll_name_to_index(*argv)) == 0) 106 invarg("dev is invalid\n", *argv); 107 break; 108 } 109 argc--; argv++; 110 } 111 112 if (rtnl_wilddump_request(&rth, af, RTM_GETLINK) < 0) { 113 perror("Cannot send dump request"); 114 return -1; 115 } 116 117 if (rtnl_dump_filter(&rth, print_token, &da) < 0) { 118 fprintf(stderr, "Dump terminated\n"); 119 return -1; 120 } 121 122 return 0; 123 } 124 125 static int iptoken_set(int argc, char **argv) 126 { 127 struct { 128 struct nlmsghdr n; 129 struct ifinfomsg ifi; 130 char buf[512]; 131 } req; 132 struct rtattr *afs, *afs6; 133 bool have_token = false, have_dev = false; 134 inet_prefix addr; 135 136 memset(&addr, 0, sizeof(addr)); 137 memset(&req, 0, sizeof(req)); 138 139 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 140 req.n.nlmsg_flags = NLM_F_REQUEST; 141 req.n.nlmsg_type = RTM_SETLINK; 142 req.ifi.ifi_family = AF_INET6; 143 144 while (argc > 0) { 145 if (strcmp(*argv, "dev") == 0) { 146 NEXT_ARG(); 147 if (!have_dev) { 148 if ((req.ifi.ifi_index = 149 ll_name_to_index(*argv)) == 0) 150 invarg("dev is invalid\n", *argv); 151 have_dev = true; 152 } 153 } else { 154 if (matches(*argv, "help") == 0) 155 usage(); 156 if (!have_token) { 157 afs = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); 158 afs6 = addattr_nest(&req.n, sizeof(req), AF_INET6); 159 get_prefix(&addr, *argv, req.ifi.ifi_family); 160 addattr_l(&req.n, sizeof(req), IFLA_INET6_TOKEN, 161 &addr.data, addr.bytelen); 162 addattr_nest_end(&req.n, afs6); 163 addattr_nest_end(&req.n, afs); 164 have_token = true; 165 } 166 } 167 argc--; argv++; 168 } 169 170 if (!have_token) { 171 fprintf(stderr, "Not enough information: token " 172 "is required.\n"); 173 return -1; 174 } 175 if (!have_dev) { 176 fprintf(stderr, "Not enough information: \"dev\" " 177 "argument is required.\n"); 178 return -1; 179 } 180 181 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) 182 return -2; 183 184 return 0; 185 } 186 187 int do_iptoken(int argc, char **argv) 188 { 189 ll_init_map(&rth); 190 191 if (argc < 1) { 192 return iptoken_list(0, NULL); 193 } else if (matches(argv[0], "list") == 0 || 194 matches(argv[0], "lst") == 0 || 195 matches(argv[0], "show") == 0) { 196 return iptoken_list(argc - 1, argv + 1); 197 } else if (matches(argv[0], "set") == 0 || 198 matches(argv[0], "add") == 0) { 199 return iptoken_set(argc - 1, argv + 1); 200 } else if (matches(argv[0], "get") == 0) { 201 return iptoken_list(argc - 1, argv + 1); 202 } else if (matches(argv[0], "help") == 0) 203 usage(); 204 205 fprintf(stderr, "Command \"%s\" is unknown, try \"ip token help\".\n", *argv); 206 exit(-1); 207 } 208