1 /* 2 * ipfou.c FOU (foo over UDP) support 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: Tom Herbert <therbert (at) google.com> 10 */ 11 12 #include <netdb.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <net/if.h> 17 #include <linux/fou.h> 18 #include <linux/genetlink.h> 19 #include <linux/ip.h> 20 #include <arpa/inet.h> 21 22 #include "libgenl.h" 23 #include "utils.h" 24 #include "ip_common.h" 25 26 static void usage(void) 27 { 28 fprintf(stderr, "Usage: ip fou add port PORT { ipproto PROTO | gue }\n"); 29 fprintf(stderr, " ip fou del port PORT\n"); 30 fprintf(stderr, "\n"); 31 fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n"); 32 fprintf(stderr, " PORT { 1..65535 }\n"); 33 34 exit(-1); 35 } 36 37 /* netlink socket */ 38 static struct rtnl_handle genl_rth = { .fd = -1 }; 39 static int genl_family = -1; 40 41 #define FOU_REQUEST(_req, _bufsiz, _cmd, _flags) \ 42 GENL_REQUEST(_req, _bufsiz, genl_family, 0, \ 43 FOU_GENL_VERSION, _cmd, _flags) 44 45 static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n, 46 bool adding) 47 { 48 __u16 port; 49 int port_set = 0; 50 __u8 ipproto, type; 51 bool gue_set = false; 52 int ipproto_set = 0; 53 54 while (argc > 0) { 55 if (!matches(*argv, "port")) { 56 NEXT_ARG(); 57 58 if (get_u16(&port, *argv, 0) || port == 0) 59 invarg("invalid port", *argv); 60 port = htons(port); 61 port_set = 1; 62 } else if (!matches(*argv, "ipproto")) { 63 struct protoent *servptr; 64 65 NEXT_ARG(); 66 67 servptr = getprotobyname(*argv); 68 if (servptr) 69 ipproto = servptr->p_proto; 70 else if (get_u8(&ipproto, *argv, 0) || ipproto == 0) 71 invarg("invalid ipproto", *argv); 72 ipproto_set = 1; 73 } else if (!matches(*argv, "gue")) { 74 gue_set = true; 75 } else { 76 fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv); 77 usage(); 78 return -1; 79 } 80 argc--, argv++; 81 } 82 83 if (!port_set) { 84 fprintf(stderr, "fou: missing port\n"); 85 return -1; 86 } 87 88 if (!ipproto_set && !gue_set && adding) { 89 fprintf(stderr, "fou: must set ipproto or gue\n"); 90 return -1; 91 } 92 93 if (ipproto_set && gue_set) { 94 fprintf(stderr, "fou: cannot set ipproto and gue\n"); 95 return -1; 96 } 97 98 type = gue_set ? FOU_ENCAP_GUE : FOU_ENCAP_DIRECT; 99 100 addattr16(n, 1024, FOU_ATTR_PORT, port); 101 addattr8(n, 1024, FOU_ATTR_TYPE, type); 102 103 if (ipproto_set) 104 addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto); 105 106 return 0; 107 } 108 109 static int do_add(int argc, char **argv) 110 { 111 FOU_REQUEST(req, 1024, FOU_CMD_ADD, NLM_F_REQUEST); 112 113 fou_parse_opt(argc, argv, &req.n, true); 114 115 if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) 116 return -2; 117 118 return 0; 119 } 120 121 static int do_del(int argc, char **argv) 122 { 123 FOU_REQUEST(req, 1024, FOU_CMD_DEL, NLM_F_REQUEST); 124 125 fou_parse_opt(argc, argv, &req.n, false); 126 127 if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) 128 return -2; 129 130 return 0; 131 } 132 133 int do_ipfou(int argc, char **argv) 134 { 135 if (genl_family < 0) { 136 if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { 137 fprintf(stderr, "Cannot open generic netlink socket\n"); 138 exit(1); 139 } 140 141 genl_family = genl_resolve_family(&genl_rth, FOU_GENL_NAME); 142 if (genl_family < 0) 143 exit(1); 144 } 145 146 if (argc < 1) 147 usage(); 148 149 if (matches(*argv, "add") == 0) 150 return do_add(argc-1, argv+1); 151 if (matches(*argv, "delete") == 0) 152 return do_del(argc-1, argv+1); 153 if (matches(*argv, "help") == 0) 154 usage(); 155 156 fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv); 157 exit(-1); 158 } 159