iptunnel.c revision 7272ddc775845d96ad1d388ced7ecdbc8612c64e
1/* 2 * iptunnel.c "ip tunnel" 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: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 * 11 * 12 * Changes: 13 * 14 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 15 * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit 16 * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag 17 */ 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22#include <unistd.h> 23#include <syslog.h> 24#include <fcntl.h> 25#include <sys/socket.h> 26#include <netinet/in.h> 27#include <arpa/inet.h> 28#include <sys/ioctl.h> 29#include <asm/byteorder.h> 30#include <linux/if.h> 31#include <linux/if_arp.h> 32#include <linux/ip.h> 33#include <linux/if_tunnel.h> 34 35#include "rt_names.h" 36#include "utils.h" 37 38static void usage(void) __attribute__((noreturn)); 39 40static void usage(void) 41{ 42 fprintf(stderr, "Usage: ip tunnel { add | change | del | show } [ NAME ]\n"); 43 fprintf(stderr, " [ mode { ipip | gre | sit } ] [ remote ADDR ] [ local ADDR ]\n"); 44 fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n"); 45 fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n"); 46 fprintf(stderr, "\n"); 47 fprintf(stderr, "Where: NAME := STRING\n"); 48 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n"); 49 fprintf(stderr, " TOS := { NUMBER | inherit }\n"); 50 fprintf(stderr, " TTL := { 1..255 | inherit }\n"); 51 fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n"); 52 exit(-1); 53} 54 55static int do_ioctl_get_ifindex(char *dev) 56{ 57 struct ifreq ifr; 58 int fd; 59 int err; 60 61 strcpy(ifr.ifr_name, dev); 62 fd = socket(AF_INET, SOCK_DGRAM, 0); 63 err = ioctl(fd, SIOCGIFINDEX, &ifr); 64 if (err) { 65 perror("ioctl"); 66 return 0; 67 } 68 close(fd); 69 return ifr.ifr_ifindex; 70} 71 72static int do_ioctl_get_iftype(char *dev) 73{ 74 struct ifreq ifr; 75 int fd; 76 int err; 77 78 strcpy(ifr.ifr_name, dev); 79 fd = socket(AF_INET, SOCK_DGRAM, 0); 80 err = ioctl(fd, SIOCGIFHWADDR, &ifr); 81 if (err) { 82 perror("ioctl"); 83 return -1; 84 } 85 close(fd); 86 return ifr.ifr_addr.sa_family; 87} 88 89 90static char * do_ioctl_get_ifname(int idx) 91{ 92 static struct ifreq ifr; 93 int fd; 94 int err; 95 96 ifr.ifr_ifindex = idx; 97 fd = socket(AF_INET, SOCK_DGRAM, 0); 98 err = ioctl(fd, SIOCGIFNAME, &ifr); 99 if (err) { 100 perror("ioctl"); 101 return NULL; 102 } 103 close(fd); 104 return ifr.ifr_name; 105} 106 107 108 109static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p) 110{ 111 struct ifreq ifr; 112 int fd; 113 int err; 114 115 strcpy(ifr.ifr_name, basedev); 116 ifr.ifr_ifru.ifru_data = (void*)p; 117 fd = socket(AF_INET, SOCK_DGRAM, 0); 118 err = ioctl(fd, SIOCGETTUNNEL, &ifr); 119 if (err) 120 perror("ioctl"); 121 close(fd); 122 return err; 123} 124 125static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p) 126{ 127 struct ifreq ifr; 128 int fd; 129 int err; 130 131 if (cmd == SIOCCHGTUNNEL && p->name[0]) 132 strcpy(ifr.ifr_name, p->name); 133 else 134 strcpy(ifr.ifr_name, basedev); 135 ifr.ifr_ifru.ifru_data = (void*)p; 136 fd = socket(AF_INET, SOCK_DGRAM, 0); 137 err = ioctl(fd, cmd, &ifr); 138 if (err) 139 perror("ioctl"); 140 close(fd); 141 return err; 142} 143 144static int do_del_ioctl(char *basedev, struct ip_tunnel_parm *p) 145{ 146 struct ifreq ifr; 147 int fd; 148 int err; 149 150 if (p->name[0]) 151 strcpy(ifr.ifr_name, p->name); 152 else 153 strcpy(ifr.ifr_name, basedev); 154 ifr.ifr_ifru.ifru_data = (void*)p; 155 fd = socket(AF_INET, SOCK_DGRAM, 0); 156 err = ioctl(fd, SIOCDELTUNNEL, &ifr); 157 if (err) 158 perror("ioctl"); 159 close(fd); 160 return err; 161} 162 163static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) 164{ 165 int count = 0; 166 char medium[IFNAMSIZ]; 167 168 memset(p, 0, sizeof(*p)); 169 memset(&medium, 0, sizeof(medium)); 170 171 p->iph.version = 4; 172 p->iph.ihl = 5; 173#ifndef IP_DF 174#define IP_DF 0x4000 /* Flag: "Don't Fragment" */ 175#endif 176 p->iph.frag_off = htons(IP_DF); 177 178 while (argc > 0) { 179 if (strcmp(*argv, "mode") == 0) { 180 NEXT_ARG(); 181 if (strcmp(*argv, "ipip") == 0 || 182 strcmp(*argv, "ip/ip") == 0) { 183 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { 184 fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); 185 exit(-1); 186 } 187 p->iph.protocol = IPPROTO_IPIP; 188 } else if (strcmp(*argv, "gre") == 0 || 189 strcmp(*argv, "gre/ip") == 0) { 190 if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { 191 fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); 192 exit(-1); 193 } 194 p->iph.protocol = IPPROTO_GRE; 195 } else if (strcmp(*argv, "sit") == 0 || 196 strcmp(*argv, "ipv6/ip") == 0) { 197 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { 198 fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); 199 exit(-1); 200 } 201 p->iph.protocol = IPPROTO_IPV6; 202 } else { 203 fprintf(stderr,"Cannot guess tunnel mode.\n"); 204 exit(-1); 205 } 206 } else if (strcmp(*argv, "key") == 0) { 207 unsigned uval; 208 NEXT_ARG(); 209 p->i_flags |= GRE_KEY; 210 p->o_flags |= GRE_KEY; 211 if (strchr(*argv, '.')) 212 p->i_key = p->o_key = get_addr32(*argv); 213 else { 214 if (get_unsigned(&uval, *argv, 0)<0) { 215 fprintf(stderr, "invalid value of \"key\"\n"); 216 exit(-1); 217 } 218 p->i_key = p->o_key = htonl(uval); 219 } 220 } else if (strcmp(*argv, "ikey") == 0) { 221 unsigned uval; 222 NEXT_ARG(); 223 p->i_flags |= GRE_KEY; 224 if (strchr(*argv, '.')) 225 p->o_key = get_addr32(*argv); 226 else { 227 if (get_unsigned(&uval, *argv, 0)<0) { 228 fprintf(stderr, "invalid value of \"ikey\"\n"); 229 exit(-1); 230 } 231 p->i_key = htonl(uval); 232 } 233 } else if (strcmp(*argv, "okey") == 0) { 234 unsigned uval; 235 NEXT_ARG(); 236 p->o_flags |= GRE_KEY; 237 if (strchr(*argv, '.')) 238 p->o_key = get_addr32(*argv); 239 else { 240 if (get_unsigned(&uval, *argv, 0)<0) { 241 fprintf(stderr, "invalid value of \"okey\"\n"); 242 exit(-1); 243 } 244 p->o_key = htonl(uval); 245 } 246 } else if (strcmp(*argv, "seq") == 0) { 247 p->i_flags |= GRE_SEQ; 248 p->o_flags |= GRE_SEQ; 249 } else if (strcmp(*argv, "iseq") == 0) { 250 p->i_flags |= GRE_SEQ; 251 } else if (strcmp(*argv, "oseq") == 0) { 252 p->o_flags |= GRE_SEQ; 253 } else if (strcmp(*argv, "csum") == 0) { 254 p->i_flags |= GRE_CSUM; 255 p->o_flags |= GRE_CSUM; 256 } else if (strcmp(*argv, "icsum") == 0) { 257 p->i_flags |= GRE_CSUM; 258 } else if (strcmp(*argv, "ocsum") == 0) { 259 p->o_flags |= GRE_CSUM; 260 } else if (strcmp(*argv, "nopmtudisc") == 0) { 261 p->iph.frag_off = 0; 262 } else if (strcmp(*argv, "pmtudisc") == 0) { 263 p->iph.frag_off = htons(IP_DF); 264 } else if (strcmp(*argv, "remote") == 0) { 265 NEXT_ARG(); 266 if (strcmp(*argv, "any")) 267 p->iph.daddr = get_addr32(*argv); 268 } else if (strcmp(*argv, "local") == 0) { 269 NEXT_ARG(); 270 if (strcmp(*argv, "any")) 271 p->iph.saddr = get_addr32(*argv); 272 } else if (strcmp(*argv, "dev") == 0) { 273 NEXT_ARG(); 274 strncpy(medium, *argv, IFNAMSIZ-1); 275 } else if (strcmp(*argv, "ttl") == 0) { 276 unsigned uval; 277 NEXT_ARG(); 278 if (strcmp(*argv, "inherit") != 0) { 279 if (get_unsigned(&uval, *argv, 0)) 280 invarg("invalid TTL\n", *argv); 281 if (uval > 255) 282 invarg("TTL must be <=255\n", *argv); 283 p->iph.ttl = uval; 284 } 285 } else if (strcmp(*argv, "tos") == 0 || 286 matches(*argv, "dsfield") == 0) { 287 __u32 uval; 288 NEXT_ARG(); 289 if (strcmp(*argv, "inherit") != 0) { 290 if (rtnl_dsfield_a2n(&uval, *argv)) 291 invarg("bad TOS value", *argv); 292 p->iph.tos = uval; 293 } else 294 p->iph.tos = 1; 295 } else { 296 if (strcmp(*argv, "name") == 0) { 297 NEXT_ARG(); 298 } 299 if (matches(*argv, "help") == 0) 300 usage(); 301 if (p->name[0]) 302 duparg2("name", *argv); 303 strncpy(p->name, *argv, IFNAMSIZ); 304 if (cmd == SIOCCHGTUNNEL && count == 0) { 305 struct ip_tunnel_parm old_p; 306 memset(&old_p, 0, sizeof(old_p)); 307 if (do_get_ioctl(*argv, &old_p)) 308 return -1; 309 *p = old_p; 310 } 311 } 312 count++; 313 argc--; argv++; 314 } 315 316 317 if (p->iph.protocol == 0) { 318 if (memcmp(p->name, "gre", 3) == 0) 319 p->iph.protocol = IPPROTO_GRE; 320 else if (memcmp(p->name, "ipip", 4) == 0) 321 p->iph.protocol = IPPROTO_IPIP; 322 else if (memcmp(p->name, "sit", 3) == 0) 323 p->iph.protocol = IPPROTO_IPV6; 324 } 325 326 if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { 327 if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { 328 fprintf(stderr, "Keys are not allowed with ipip and sit.\n"); 329 return -1; 330 } 331 } 332 333 if (medium[0]) { 334 p->link = do_ioctl_get_ifindex(medium); 335 if (p->link == 0) 336 return -1; 337 } 338 339 if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { 340 p->i_key = p->iph.daddr; 341 p->i_flags |= GRE_KEY; 342 } 343 if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { 344 p->o_key = p->iph.daddr; 345 p->o_flags |= GRE_KEY; 346 } 347 if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { 348 fprintf(stderr, "Broadcast tunnel requires a source address.\n"); 349 return -1; 350 } 351 return 0; 352} 353 354 355static int do_add(int cmd, int argc, char **argv) 356{ 357 struct ip_tunnel_parm p; 358 359 if (parse_args(argc, argv, cmd, &p) < 0) 360 return -1; 361 362 if (p.iph.ttl && p.iph.frag_off == 0) { 363 fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n"); 364 return -1; 365 } 366 367 switch (p.iph.protocol) { 368 case IPPROTO_IPIP: 369 return do_add_ioctl(cmd, "tunl0", &p); 370 case IPPROTO_GRE: 371 return do_add_ioctl(cmd, "gre0", &p); 372 case IPPROTO_IPV6: 373 return do_add_ioctl(cmd, "sit0", &p); 374 default: 375 fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n"); 376 return -1; 377 } 378 return -1; 379} 380 381int do_del(int argc, char **argv) 382{ 383 struct ip_tunnel_parm p; 384 385 if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0) 386 return -1; 387 388 switch (p.iph.protocol) { 389 case IPPROTO_IPIP: 390 return do_del_ioctl("tunl0", &p); 391 case IPPROTO_GRE: 392 return do_del_ioctl("gre0", &p); 393 case IPPROTO_IPV6: 394 return do_del_ioctl("sit0", &p); 395 default: 396 return do_del_ioctl(p.name, &p); 397 } 398 return -1; 399} 400 401void print_tunnel(struct ip_tunnel_parm *p) 402{ 403 char s1[1024]; 404 char s2[1024]; 405 char s3[64]; 406 char s4[64]; 407 408 inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3)); 409 inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4)); 410 411 /* Do not use format_host() for local addr, 412 * symbolic name will not be useful. 413 */ 414 printf("%s: %s/ip remote %s local %s ", 415 p->name, 416 p->iph.protocol == IPPROTO_IPIP ? "ip" : 417 (p->iph.protocol == IPPROTO_GRE ? "gre" : 418 (p->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")), 419 p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any", 420 p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any"); 421 422 if (p->link) { 423 char *n = do_ioctl_get_ifname(p->link); 424 if (n) 425 printf(" dev %s ", n); 426 } 427 428 if (p->iph.ttl) 429 printf(" ttl %d ", p->iph.ttl); 430 else 431 printf(" ttl inherit "); 432 433 if (p->iph.tos) { 434 SPRINT_BUF(b1); 435 printf(" tos"); 436 if (p->iph.tos&1) 437 printf(" inherit"); 438 if (p->iph.tos&~1) 439 printf("%c%s ", p->iph.tos&1 ? '/' : ' ', 440 rtnl_dsfield_n2a(p->iph.tos&~1, b1, sizeof(b1))); 441 } 442 443 if (!(p->iph.frag_off&htons(IP_DF))) 444 printf(" nopmtudisc"); 445 446 if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key) 447 printf(" key %s", s3); 448 else if ((p->i_flags|p->o_flags)&GRE_KEY) { 449 if (p->i_flags&GRE_KEY) 450 printf(" ikey %s ", s3); 451 if (p->o_flags&GRE_KEY) 452 printf(" okey %s ", s4); 453 } 454 455 if (p->i_flags&GRE_SEQ) 456 printf("%s Drop packets out of sequence.\n", _SL_); 457 if (p->i_flags&GRE_CSUM) 458 printf("%s Checksum in received packet is required.", _SL_); 459 if (p->o_flags&GRE_SEQ) 460 printf("%s Sequence packets on output.", _SL_); 461 if (p->o_flags&GRE_CSUM) 462 printf("%s Checksum output packets.", _SL_); 463} 464 465static int do_tunnels_list(struct ip_tunnel_parm *p) 466{ 467 char name[IFNAMSIZ]; 468 unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, 469 rx_fifo, rx_frame, 470 tx_bytes, tx_packets, tx_errs, tx_drops, 471 tx_fifo, tx_colls, tx_carrier, rx_multi; 472 int type; 473 struct ip_tunnel_parm p1; 474 475 char buf[512]; 476 FILE *fp = fopen("/proc/net/dev", "r"); 477 if (fp == NULL) { 478 perror("fopen"); 479 return -1; 480 } 481 482 fgets(buf, sizeof(buf), fp); 483 fgets(buf, sizeof(buf), fp); 484 485 while (fgets(buf, sizeof(buf), fp) != NULL) { 486 char *ptr; 487 buf[sizeof(buf) - 1] = 0; 488 if ((ptr = strchr(buf, ':')) == NULL || 489 (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { 490 fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n"); 491 return -1; 492 } 493 if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld", 494 &rx_bytes, &rx_packets, &rx_errs, &rx_drops, 495 &rx_fifo, &rx_frame, &rx_multi, 496 &tx_bytes, &tx_packets, &tx_errs, &tx_drops, 497 &tx_fifo, &tx_colls, &tx_carrier) != 14) 498 continue; 499 if (p->name[0] && strcmp(p->name, name)) 500 continue; 501 type = do_ioctl_get_iftype(name); 502 if (type == -1) { 503 fprintf(stderr, "Failed to get type of [%s]\n", name); 504 continue; 505 } 506 if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) 507 continue; 508 memset(&p1, 0, sizeof(p1)); 509 if (do_get_ioctl(name, &p1)) 510 continue; 511 if ((p->link && p1.link != p->link) || 512 (p->name[0] && strcmp(p1.name, p->name)) || 513 (p->iph.daddr && p1.iph.daddr != p->iph.daddr) || 514 (p->iph.saddr && p1.iph.saddr != p->iph.saddr) || 515 (p->i_key && p1.i_key != p->i_key)) 516 continue; 517 print_tunnel(&p1); 518 if (show_stats) { 519 printf("%s", _SL_); 520 printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_); 521 printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s", 522 rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_); 523 printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_); 524 printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld", 525 tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops); 526 } 527 printf("\n"); 528 } 529 return 0; 530} 531 532static int do_show(int argc, char **argv) 533{ 534 int err; 535 struct ip_tunnel_parm p; 536 537 if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) 538 return -1; 539 540 switch (p.iph.protocol) { 541 case IPPROTO_IPIP: 542 err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p); 543 break; 544 case IPPROTO_GRE: 545 err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p); 546 break; 547 case IPPROTO_IPV6: 548 err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p); 549 break; 550 default: 551 do_tunnels_list(&p); 552 return 0; 553 } 554 if (err) 555 return -1; 556 557 print_tunnel(&p); 558 printf("\n"); 559 return 0; 560} 561 562int do_iptunnel(int argc, char **argv) 563{ 564 if (argc > 0) { 565 if (matches(*argv, "add") == 0) 566 return do_add(SIOCADDTUNNEL, argc-1, argv+1); 567 if (matches(*argv, "change") == 0) 568 return do_add(SIOCCHGTUNNEL, argc-1, argv+1); 569 if (matches(*argv, "del") == 0) 570 return do_del(argc-1, argv+1); 571 if (matches(*argv, "show") == 0 || 572 matches(*argv, "lst") == 0 || 573 matches(*argv, "list") == 0) 574 return do_show(argc-1, argv+1); 575 if (matches(*argv, "help") == 0) 576 usage(); 577 } else 578 return do_show(0, NULL); 579 580 fprintf(stderr, "Command \"%s\" is unknown, try \"ip tunnel help\".\n", *argv); 581 exit(-1); 582} 583