link_iptnl.c revision 1ce2de97386e38c258ee2048a80ee28d0e8bad01
1/* 2 * link_iptnl.c ipip and sit driver module 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: Nicolas Dichtel <nicolas.dichtel@6wind.com> 10 * 11 */ 12 13#include <string.h> 14#include <net/if.h> 15#include <sys/types.h> 16#include <sys/socket.h> 17#include <arpa/inet.h> 18 19#include <linux/ip.h> 20#include <linux/if_tunnel.h> 21#include "rt_names.h" 22#include "utils.h" 23#include "ip_common.h" 24#include "tunnel.h" 25 26static void usage(int sit) __attribute__((noreturn)); 27static void usage(int sit) 28{ 29 fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n"); 30 fprintf(stderr, " type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n"); 31 fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n"); 32 fprintf(stderr, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n"); 33 if (sit) 34 fprintf(stderr, " [ isatap ]\n"); 35 fprintf(stderr, "\n"); 36 fprintf(stderr, "Where: NAME := STRING\n"); 37 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n"); 38 fprintf(stderr, " TOS := { NUMBER | inherit }\n"); 39 fprintf(stderr, " TTL := { 1..255 | inherit }\n"); 40 exit(-1); 41} 42 43static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, 44 struct nlmsghdr *n) 45{ 46 struct { 47 struct nlmsghdr n; 48 struct ifinfomsg i; 49 char buf[2048]; 50 } req; 51 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); 52 struct rtattr *tb[IFLA_MAX + 1]; 53 struct rtattr *linkinfo[IFLA_INFO_MAX+1]; 54 struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; 55 int len; 56 __u32 link = 0; 57 __u32 laddr = 0; 58 __u32 raddr = 0; 59 __u8 ttl = 0; 60 __u8 tos = 0; 61 __u8 pmtudisc = 1; 62 __u16 iflags = 0; 63 struct in6_addr ip6rdprefix; 64 __u16 ip6rdprefixlen = 0; 65 __u32 ip6rdrelayprefix = 0; 66 __u16 ip6rdrelayprefixlen = 0; 67 68 memset(&ip6rdprefix, 0, sizeof(ip6rdprefix)); 69 70 if (!(n->nlmsg_flags & NLM_F_CREATE)) { 71 memset(&req, 0, sizeof(req)); 72 73 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); 74 req.n.nlmsg_flags = NLM_F_REQUEST; 75 req.n.nlmsg_type = RTM_GETLINK; 76 req.i.ifi_family = preferred_family; 77 req.i.ifi_index = ifi->ifi_index; 78 79 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { 80get_failed: 81 fprintf(stderr, 82 "Failed to get existing tunnel info.\n"); 83 return -1; 84 } 85 86 len = req.n.nlmsg_len; 87 len -= NLMSG_LENGTH(sizeof(*ifi)); 88 if (len < 0) 89 goto get_failed; 90 91 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); 92 93 if (!tb[IFLA_LINKINFO]) 94 goto get_failed; 95 96 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); 97 98 if (!linkinfo[IFLA_INFO_DATA]) 99 goto get_failed; 100 101 parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, 102 linkinfo[IFLA_INFO_DATA]); 103 104 if (iptuninfo[IFLA_IPTUN_LOCAL]) 105 laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]); 106 107 if (iptuninfo[IFLA_IPTUN_REMOTE]) 108 raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]); 109 110 if (iptuninfo[IFLA_IPTUN_TTL]) 111 ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); 112 113 if (iptuninfo[IFLA_IPTUN_TOS]) 114 tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]); 115 116 if (iptuninfo[IFLA_IPTUN_PMTUDISC]) 117 pmtudisc = 118 rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]); 119 120 if (iptuninfo[IFLA_IPTUN_FLAGS]) 121 iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]); 122 123 if (iptuninfo[IFLA_IPTUN_LINK]) 124 link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]); 125 126 if (iptuninfo[IFLA_IPTUN_6RD_PREFIX]) 127 memcpy(&ip6rdprefix, 128 RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]), 129 sizeof(laddr)); 130 131 if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]) 132 ip6rdprefixlen = 133 rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]); 134 135 if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]) 136 ip6rdrelayprefix = 137 rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]); 138 139 if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) 140 ip6rdrelayprefixlen = 141 rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); 142 } 143 144 while (argc > 0) { 145 if (strcmp(*argv, "remote") == 0) { 146 NEXT_ARG(); 147 if (strcmp(*argv, "any")) 148 raddr = get_addr32(*argv); 149 else 150 raddr = 0; 151 } else if (strcmp(*argv, "local") == 0) { 152 NEXT_ARG(); 153 if (strcmp(*argv, "any")) 154 laddr = get_addr32(*argv); 155 else 156 laddr = 0; 157 } else if (matches(*argv, "dev") == 0) { 158 NEXT_ARG(); 159 link = if_nametoindex(*argv); 160 if (link == 0) 161 invarg("\"dev\" is invalid", *argv); 162 } else if (strcmp(*argv, "ttl") == 0 || 163 strcmp(*argv, "hoplimit") == 0) { 164 NEXT_ARG(); 165 if (strcmp(*argv, "inherit") != 0) { 166 if (get_u8(&ttl, *argv, 0)) 167 invarg("invalid TTL\n", *argv); 168 } else 169 ttl = 0; 170 } else if (strcmp(*argv, "tos") == 0 || 171 strcmp(*argv, "tclass") == 0 || 172 matches(*argv, "dsfield") == 0) { 173 __u32 uval; 174 NEXT_ARG(); 175 if (strcmp(*argv, "inherit") != 0) { 176 if (rtnl_dsfield_a2n(&uval, *argv)) 177 invarg("bad TOS value", *argv); 178 tos = uval; 179 } else 180 tos = 1; 181 } else if (strcmp(*argv, "nopmtudisc") == 0) { 182 pmtudisc = 0; 183 } else if (strcmp(*argv, "pmtudisc") == 0) { 184 pmtudisc = 1; 185 } else if (strcmp(lu->id, "sit") == 0 && 186 strcmp(*argv, "isatap") == 0) { 187 iflags |= SIT_ISATAP; 188 } else if (strcmp(*argv, "6rd-prefix") == 0) { 189 inet_prefix prefix; 190 NEXT_ARG(); 191 if (get_prefix(&prefix, *argv, AF_INET6)) 192 invarg("invalid 6rd_prefix\n", *argv); 193 memcpy(&ip6rdprefix, prefix.data, 16); 194 ip6rdprefixlen = prefix.bitlen; 195 } else if (strcmp(*argv, "6rd-relay_prefix") == 0) { 196 inet_prefix prefix; 197 NEXT_ARG(); 198 if (get_prefix(&prefix, *argv, AF_INET)) 199 invarg("invalid 6rd-relay_prefix\n", *argv); 200 memcpy(&ip6rdrelayprefix, prefix.data, 4); 201 ip6rdrelayprefixlen = prefix.bitlen; 202 } else if (strcmp(*argv, "6rd-reset") == 0) { 203 inet_prefix prefix; 204 get_prefix(&prefix, "2002::", AF_INET6); 205 memcpy(&ip6rdprefix, prefix.data, 16); 206 ip6rdprefixlen = 16; 207 ip6rdrelayprefix = 0; 208 ip6rdrelayprefixlen = 0; 209 } else 210 usage(strcmp(lu->id, "sit") == 0); 211 argc--, argv++; 212 } 213 214 if (ttl && pmtudisc == 0) { 215 fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n"); 216 exit(-1); 217 } 218 219 addattr32(n, 1024, IFLA_IPTUN_LINK, link); 220 addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr); 221 addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr); 222 addattr8(n, 1024, IFLA_IPTUN_TTL, ttl); 223 addattr8(n, 1024, IFLA_IPTUN_TOS, tos); 224 addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc); 225 if (strcmp(lu->id, "sit") == 0) { 226 addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); 227 if (ip6rdprefixlen) { 228 addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, 229 &ip6rdprefix, sizeof(ip6rdprefix)); 230 addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN, 231 ip6rdprefixlen); 232 addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX, 233 ip6rdrelayprefix); 234 addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, 235 ip6rdrelayprefixlen); 236 } 237 } 238 239 return 0; 240} 241 242static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 243{ 244 char s1[1024]; 245 char s2[64]; 246 const char *local = "any"; 247 const char *remote = "any"; 248 249 if (!tb) 250 return; 251 252 if (tb[IFLA_IPTUN_REMOTE]) { 253 unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]); 254 255 if (addr) 256 remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); 257 } 258 259 fprintf(f, "remote %s ", remote); 260 261 if (tb[IFLA_IPTUN_LOCAL]) { 262 unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]); 263 264 if (addr) 265 local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); 266 } 267 268 fprintf(f, "local %s ", local); 269 270 if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { 271 unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); 272 const char *n = if_indextoname(link, s2); 273 274 if (n) 275 fprintf(f, "dev %s ", n); 276 else 277 fprintf(f, "dev %u ", link); 278 } 279 280 if (tb[IFLA_IPTUN_TTL] && rta_getattr_u8(tb[IFLA_IPTUN_TTL])) 281 fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_IPTUN_TTL])); 282 else 283 fprintf(f, "ttl inherit "); 284 285 if (tb[IFLA_IPTUN_TOS] && rta_getattr_u8(tb[IFLA_IPTUN_TOS])) { 286 int tos = rta_getattr_u8(tb[IFLA_IPTUN_TOS]); 287 288 fputs("tos ", f); 289 if (tos == 1) 290 fputs("inherit ", f); 291 else 292 fprintf(f, "0x%x ", tos); 293 } 294 295 if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC])) 296 fprintf(f, "pmtudisc "); 297 else 298 fprintf(f, "nopmtudisc "); 299 300 if (tb[IFLA_IPTUN_FLAGS]) { 301 __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]); 302 303 if (iflags & SIT_ISATAP) 304 fprintf(f, "isatap "); 305 } 306 307 if (tb[IFLA_IPTUN_6RD_PREFIXLEN] && 308 *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIXLEN])) { 309 __u16 prefixlen = rta_getattr_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]); 310 __u16 relayprefixlen = 311 rta_getattr_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); 312 __u32 relayprefix = 313 rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]); 314 315 printf("6rd-prefix %s/%u ", 316 inet_ntop(AF_INET6, RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]), 317 s1, sizeof(s1)), 318 prefixlen); 319 if (relayprefix) { 320 printf("6rd-relay_prefix %s/%u ", 321 format_host(AF_INET, 4, &relayprefix, s1, 322 sizeof(s1)), 323 relayprefixlen); 324 } 325 } 326} 327 328struct link_util ipip_link_util = { 329 .id = "ipip", 330 .maxattr = IFLA_IPTUN_MAX, 331 .parse_opt = iptunnel_parse_opt, 332 .print_opt = iptunnel_print_opt, 333}; 334 335struct link_util sit_link_util = { 336 .id = "sit", 337 .maxattr = IFLA_IPTUN_MAX, 338 .parse_opt = iptunnel_parse_opt, 339 .print_opt = iptunnel_print_opt, 340}; 341