PageRenderTime 35ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/user/iproute2/iproute2-2.6.29-1/ip/iptunnel.c

https://bitbucket.org/thelearninglabs/uclinux-distro-tll-public
C | 510 lines | 442 code | 42 blank | 26 comment | 217 complexity | 35275410e6fbf7f62c2ed35bf30bad25 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-3.0, Unlicense, GPL-2.0, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0, ISC, MIT, 0BSD, LGPL-2.0
  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. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <arpa/inet.h>
  25. #include <sys/ioctl.h>
  26. #include <linux/if.h>
  27. #include <linux/if_arp.h>
  28. #include <linux/ip.h>
  29. #include <linux/if_tunnel.h>
  30. #include "rt_names.h"
  31. #include "utils.h"
  32. #include "ip_common.h"
  33. #include "tunnel.h"
  34. static void usage(void) __attribute__((noreturn));
  35. static void usage(void)
  36. {
  37. fprintf(stderr, "Usage: ip tunnel { add | change | del | show } [ NAME ]\n");
  38. fprintf(stderr, " [ mode { ipip | gre | sit | isatap } ] [ remote ADDR ] [ local ADDR ]\n");
  39. fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
  40. fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
  41. fprintf(stderr, "\n");
  42. fprintf(stderr, "Where: NAME := STRING\n");
  43. fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
  44. fprintf(stderr, " TOS := { NUMBER | inherit }\n");
  45. fprintf(stderr, " TTL := { 1..255 | inherit }\n");
  46. fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
  47. exit(-1);
  48. }
  49. static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
  50. {
  51. int count = 0;
  52. char medium[IFNAMSIZ];
  53. int isatap = 0;
  54. memset(p, 0, sizeof(*p));
  55. memset(&medium, 0, sizeof(medium));
  56. p->iph.version = 4;
  57. p->iph.ihl = 5;
  58. #ifndef IP_DF
  59. #define IP_DF 0x4000 /* Flag: "Don't Fragment" */
  60. #endif
  61. p->iph.frag_off = htons(IP_DF);
  62. while (argc > 0) {
  63. if (strcmp(*argv, "mode") == 0) {
  64. NEXT_ARG();
  65. if (strcmp(*argv, "ipip") == 0 ||
  66. strcmp(*argv, "ip/ip") == 0) {
  67. if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
  68. fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
  69. exit(-1);
  70. }
  71. p->iph.protocol = IPPROTO_IPIP;
  72. } else if (strcmp(*argv, "gre") == 0 ||
  73. strcmp(*argv, "gre/ip") == 0) {
  74. if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
  75. fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
  76. exit(-1);
  77. }
  78. p->iph.protocol = IPPROTO_GRE;
  79. } else if (strcmp(*argv, "sit") == 0 ||
  80. strcmp(*argv, "ipv6/ip") == 0) {
  81. if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
  82. fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
  83. exit(-1);
  84. }
  85. p->iph.protocol = IPPROTO_IPV6;
  86. } else if (strcmp(*argv, "isatap") == 0) {
  87. if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
  88. fprintf(stderr, "You managed to ask for more than one tunnel mode.\n");
  89. exit(-1);
  90. }
  91. p->iph.protocol = IPPROTO_IPV6;
  92. isatap++;
  93. } else {
  94. fprintf(stderr,"Cannot guess tunnel mode.\n");
  95. exit(-1);
  96. }
  97. } else if (strcmp(*argv, "key") == 0) {
  98. unsigned uval;
  99. NEXT_ARG();
  100. p->i_flags |= GRE_KEY;
  101. p->o_flags |= GRE_KEY;
  102. if (strchr(*argv, '.'))
  103. p->i_key = p->o_key = get_addr32(*argv);
  104. else {
  105. if (get_unsigned(&uval, *argv, 0)<0) {
  106. fprintf(stderr, "invalid value of \"key\"\n");
  107. exit(-1);
  108. }
  109. p->i_key = p->o_key = htonl(uval);
  110. }
  111. } else if (strcmp(*argv, "ikey") == 0) {
  112. unsigned uval;
  113. NEXT_ARG();
  114. p->i_flags |= GRE_KEY;
  115. if (strchr(*argv, '.'))
  116. p->i_key = get_addr32(*argv);
  117. else {
  118. if (get_unsigned(&uval, *argv, 0)<0) {
  119. fprintf(stderr, "invalid value of \"ikey\"\n");
  120. exit(-1);
  121. }
  122. p->i_key = htonl(uval);
  123. }
  124. } else if (strcmp(*argv, "okey") == 0) {
  125. unsigned uval;
  126. NEXT_ARG();
  127. p->o_flags |= GRE_KEY;
  128. if (strchr(*argv, '.'))
  129. p->o_key = get_addr32(*argv);
  130. else {
  131. if (get_unsigned(&uval, *argv, 0)<0) {
  132. fprintf(stderr, "invalid value of \"okey\"\n");
  133. exit(-1);
  134. }
  135. p->o_key = htonl(uval);
  136. }
  137. } else if (strcmp(*argv, "seq") == 0) {
  138. p->i_flags |= GRE_SEQ;
  139. p->o_flags |= GRE_SEQ;
  140. } else if (strcmp(*argv, "iseq") == 0) {
  141. p->i_flags |= GRE_SEQ;
  142. } else if (strcmp(*argv, "oseq") == 0) {
  143. p->o_flags |= GRE_SEQ;
  144. } else if (strcmp(*argv, "csum") == 0) {
  145. p->i_flags |= GRE_CSUM;
  146. p->o_flags |= GRE_CSUM;
  147. } else if (strcmp(*argv, "icsum") == 0) {
  148. p->i_flags |= GRE_CSUM;
  149. } else if (strcmp(*argv, "ocsum") == 0) {
  150. p->o_flags |= GRE_CSUM;
  151. } else if (strcmp(*argv, "nopmtudisc") == 0) {
  152. p->iph.frag_off = 0;
  153. } else if (strcmp(*argv, "pmtudisc") == 0) {
  154. p->iph.frag_off = htons(IP_DF);
  155. } else if (strcmp(*argv, "remote") == 0) {
  156. NEXT_ARG();
  157. if (strcmp(*argv, "any"))
  158. p->iph.daddr = get_addr32(*argv);
  159. } else if (strcmp(*argv, "local") == 0) {
  160. NEXT_ARG();
  161. if (strcmp(*argv, "any"))
  162. p->iph.saddr = get_addr32(*argv);
  163. } else if (strcmp(*argv, "dev") == 0) {
  164. NEXT_ARG();
  165. strncpy(medium, *argv, IFNAMSIZ-1);
  166. } else if (strcmp(*argv, "ttl") == 0 ||
  167. strcmp(*argv, "hoplimit") == 0) {
  168. unsigned uval;
  169. NEXT_ARG();
  170. if (strcmp(*argv, "inherit") != 0) {
  171. if (get_unsigned(&uval, *argv, 0))
  172. invarg("invalid TTL\n", *argv);
  173. if (uval > 255)
  174. invarg("TTL must be <=255\n", *argv);
  175. p->iph.ttl = uval;
  176. }
  177. } else if (strcmp(*argv, "tos") == 0 ||
  178. strcmp(*argv, "tclass") == 0 ||
  179. matches(*argv, "dsfield") == 0) {
  180. __u32 uval;
  181. NEXT_ARG();
  182. if (strcmp(*argv, "inherit") != 0) {
  183. if (rtnl_dsfield_a2n(&uval, *argv))
  184. invarg("bad TOS value", *argv);
  185. p->iph.tos = uval;
  186. } else
  187. p->iph.tos = 1;
  188. } else {
  189. if (strcmp(*argv, "name") == 0) {
  190. NEXT_ARG();
  191. } else if (matches(*argv, "help") == 0)
  192. usage();
  193. if (p->name[0])
  194. duparg2("name", *argv);
  195. strncpy(p->name, *argv, IFNAMSIZ);
  196. if (cmd == SIOCCHGTUNNEL && count == 0) {
  197. struct ip_tunnel_parm old_p;
  198. memset(&old_p, 0, sizeof(old_p));
  199. if (tnl_get_ioctl(*argv, &old_p))
  200. return -1;
  201. *p = old_p;
  202. }
  203. }
  204. count++;
  205. argc--; argv++;
  206. }
  207. if (p->iph.protocol == 0) {
  208. if (memcmp(p->name, "gre", 3) == 0)
  209. p->iph.protocol = IPPROTO_GRE;
  210. else if (memcmp(p->name, "ipip", 4) == 0)
  211. p->iph.protocol = IPPROTO_IPIP;
  212. else if (memcmp(p->name, "sit", 3) == 0)
  213. p->iph.protocol = IPPROTO_IPV6;
  214. else if (memcmp(p->name, "isatap", 6) == 0) {
  215. p->iph.protocol = IPPROTO_IPV6;
  216. isatap++;
  217. }
  218. }
  219. if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
  220. if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
  221. fprintf(stderr, "Keys are not allowed with ipip and sit.\n");
  222. return -1;
  223. }
  224. }
  225. if (medium[0]) {
  226. p->link = tnl_ioctl_get_ifindex(medium);
  227. if (p->link == 0)
  228. return -1;
  229. }
  230. if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
  231. p->i_key = p->iph.daddr;
  232. p->i_flags |= GRE_KEY;
  233. }
  234. if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
  235. p->o_key = p->iph.daddr;
  236. p->o_flags |= GRE_KEY;
  237. }
  238. if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
  239. fprintf(stderr, "Broadcast tunnel requires a source address.\n");
  240. return -1;
  241. }
  242. if (isatap) {
  243. if (p->iph.daddr) {
  244. fprintf(stderr, "no remote with isatap.\n");
  245. return -1;
  246. }
  247. p->i_flags |= SIT_ISATAP;
  248. }
  249. return 0;
  250. }
  251. static int do_add(int cmd, int argc, char **argv)
  252. {
  253. struct ip_tunnel_parm p;
  254. if (parse_args(argc, argv, cmd, &p) < 0)
  255. return -1;
  256. if (p.iph.ttl && p.iph.frag_off == 0) {
  257. fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
  258. return -1;
  259. }
  260. switch (p.iph.protocol) {
  261. case IPPROTO_IPIP:
  262. return tnl_add_ioctl(cmd, "tunl0", p.name, &p);
  263. case IPPROTO_GRE:
  264. return tnl_add_ioctl(cmd, "gre0", p.name, &p);
  265. case IPPROTO_IPV6:
  266. return tnl_add_ioctl(cmd, "sit0", p.name, &p);
  267. default:
  268. fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n");
  269. return -1;
  270. }
  271. return -1;
  272. }
  273. static int do_del(int argc, char **argv)
  274. {
  275. struct ip_tunnel_parm p;
  276. if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
  277. return -1;
  278. switch (p.iph.protocol) {
  279. case IPPROTO_IPIP:
  280. return tnl_del_ioctl("tunl0", p.name, &p);
  281. case IPPROTO_GRE:
  282. return tnl_del_ioctl("gre0", p.name, &p);
  283. case IPPROTO_IPV6:
  284. return tnl_del_ioctl("sit0", p.name, &p);
  285. default:
  286. return tnl_del_ioctl(p.name, p.name, &p);
  287. }
  288. return -1;
  289. }
  290. static void print_tunnel(struct ip_tunnel_parm *p)
  291. {
  292. char s1[1024];
  293. char s2[1024];
  294. char s3[64];
  295. char s4[64];
  296. inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3));
  297. inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4));
  298. /* Do not use format_host() for local addr,
  299. * symbolic name will not be useful.
  300. */
  301. printf("%s: %s/ip remote %s local %s ",
  302. p->name,
  303. tnl_strproto(p->iph.protocol),
  304. p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any",
  305. p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any");
  306. if (p->link) {
  307. char *n = tnl_ioctl_get_ifname(p->link);
  308. if (n)
  309. printf(" dev %s ", n);
  310. }
  311. if (p->iph.ttl)
  312. printf(" ttl %d ", p->iph.ttl);
  313. else
  314. printf(" ttl inherit ");
  315. if (p->iph.tos) {
  316. SPRINT_BUF(b1);
  317. printf(" tos");
  318. if (p->iph.tos&1)
  319. printf(" inherit");
  320. if (p->iph.tos&~1)
  321. printf("%c%s ", p->iph.tos&1 ? '/' : ' ',
  322. rtnl_dsfield_n2a(p->iph.tos&~1, b1, sizeof(b1)));
  323. }
  324. if (!(p->iph.frag_off&htons(IP_DF)))
  325. printf(" nopmtudisc");
  326. if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
  327. printf(" key %s", s3);
  328. else if ((p->i_flags|p->o_flags)&GRE_KEY) {
  329. if (p->i_flags&GRE_KEY)
  330. printf(" ikey %s ", s3);
  331. if (p->o_flags&GRE_KEY)
  332. printf(" okey %s ", s4);
  333. }
  334. if (p->i_flags&GRE_SEQ)
  335. printf("%s Drop packets out of sequence.\n", _SL_);
  336. if (p->i_flags&GRE_CSUM)
  337. printf("%s Checksum in received packet is required.", _SL_);
  338. if (p->o_flags&GRE_SEQ)
  339. printf("%s Sequence packets on output.", _SL_);
  340. if (p->o_flags&GRE_CSUM)
  341. printf("%s Checksum output packets.", _SL_);
  342. }
  343. static int do_tunnels_list(struct ip_tunnel_parm *p)
  344. {
  345. char name[IFNAMSIZ];
  346. unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
  347. rx_fifo, rx_frame,
  348. tx_bytes, tx_packets, tx_errs, tx_drops,
  349. tx_fifo, tx_colls, tx_carrier, rx_multi;
  350. int type;
  351. struct ip_tunnel_parm p1;
  352. char buf[512];
  353. FILE *fp = fopen("/proc/net/dev", "r");
  354. if (fp == NULL) {
  355. perror("fopen");
  356. return -1;
  357. }
  358. fgets(buf, sizeof(buf), fp);
  359. fgets(buf, sizeof(buf), fp);
  360. while (fgets(buf, sizeof(buf), fp) != NULL) {
  361. char *ptr;
  362. buf[sizeof(buf) - 1] = 0;
  363. if ((ptr = strchr(buf, ':')) == NULL ||
  364. (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
  365. fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
  366. return -1;
  367. }
  368. if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
  369. &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
  370. &rx_fifo, &rx_frame, &rx_multi,
  371. &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
  372. &tx_fifo, &tx_colls, &tx_carrier) != 14)
  373. continue;
  374. if (p->name[0] && strcmp(p->name, name))
  375. continue;
  376. type = tnl_ioctl_get_iftype(name);
  377. if (type == -1) {
  378. fprintf(stderr, "Failed to get type of [%s]\n", name);
  379. continue;
  380. }
  381. if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
  382. continue;
  383. memset(&p1, 0, sizeof(p1));
  384. if (tnl_get_ioctl(name, &p1))
  385. continue;
  386. if ((p->link && p1.link != p->link) ||
  387. (p->name[0] && strcmp(p1.name, p->name)) ||
  388. (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
  389. (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
  390. (p->i_key && p1.i_key != p->i_key))
  391. continue;
  392. print_tunnel(&p1);
  393. if (show_stats) {
  394. printf("%s", _SL_);
  395. printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
  396. printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
  397. rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
  398. printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_);
  399. printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
  400. tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
  401. }
  402. printf("\n");
  403. }
  404. return 0;
  405. }
  406. static int do_show(int argc, char **argv)
  407. {
  408. int err;
  409. struct ip_tunnel_parm p;
  410. if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
  411. return -1;
  412. switch (p.iph.protocol) {
  413. case IPPROTO_IPIP:
  414. err = tnl_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
  415. break;
  416. case IPPROTO_GRE:
  417. err = tnl_get_ioctl(p.name[0] ? p.name : "gre0", &p);
  418. break;
  419. case IPPROTO_IPV6:
  420. err = tnl_get_ioctl(p.name[0] ? p.name : "sit0", &p);
  421. break;
  422. default:
  423. do_tunnels_list(&p);
  424. return 0;
  425. }
  426. if (err)
  427. return -1;
  428. print_tunnel(&p);
  429. printf("\n");
  430. return 0;
  431. }
  432. int do_iptunnel(int argc, char **argv)
  433. {
  434. switch (preferred_family) {
  435. case AF_UNSPEC:
  436. preferred_family = AF_INET;
  437. break;
  438. case AF_INET:
  439. break;
  440. /*
  441. * This is silly enough but we have no easy way to make it
  442. * protocol-independent because of unarranged structure between
  443. * IPv4 and IPv6.
  444. */
  445. case AF_INET6:
  446. //return do_ip6tunnel(argc, argv);
  447. default:
  448. fprintf(stderr, "Unsupported family:%d\n", preferred_family);
  449. exit(-1);
  450. }
  451. if (argc > 0) {
  452. if (matches(*argv, "add") == 0)
  453. return do_add(SIOCADDTUNNEL, argc-1, argv+1);
  454. if (matches(*argv, "change") == 0)
  455. return do_add(SIOCCHGTUNNEL, argc-1, argv+1);
  456. if (matches(*argv, "del") == 0)
  457. return do_del(argc-1, argv+1);
  458. if (matches(*argv, "show") == 0 ||
  459. matches(*argv, "lst") == 0 ||
  460. matches(*argv, "list") == 0)
  461. return do_show(argc-1, argv+1);
  462. if (matches(*argv, "help") == 0)
  463. usage();
  464. } else
  465. return do_show(0, NULL);
  466. fprintf(stderr, "Command \"%s\" is unknown, try \"ip tunnel help\".\n", *argv);
  467. exit(-1);
  468. }