1 /* 2 * m_tunnel_key.c ip tunnel manipulation 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: Amir Vadai <amir (at) vadai.me> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <string.h> 16 #include <linux/if_ether.h> 17 #include "utils.h" 18 #include "rt_names.h" 19 #include "tc_util.h" 20 #include <linux/tc_act/tc_tunnel_key.h> 21 22 static void explain(void) 23 { 24 fprintf(stderr, "Usage: tunnel_key unset\n"); 25 fprintf(stderr, " tunnel_key set <TUNNEL_KEY>\n"); 26 fprintf(stderr, 27 "Where TUNNEL_KEY is a combination of:\n" 28 "id <TUNNELID> (mandatory)\n" 29 "src_ip <IP> (mandatory)\n" 30 "dst_ip <IP> (mandatory)\n" 31 "dst_port <UDP_PORT>\n" 32 "csum | nocsum (default is \"csum\")\n"); 33 } 34 35 static void usage(void) 36 { 37 explain(); 38 exit(-1); 39 } 40 41 static int tunnel_key_parse_ip_addr(const char *str, int addr4_type, 42 int addr6_type, struct nlmsghdr *n) 43 { 44 inet_prefix addr; 45 int ret; 46 47 ret = get_addr(&addr, str, AF_UNSPEC); 48 if (ret) 49 return ret; 50 51 addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type, 52 addr.data, addr.bytelen); 53 54 return 0; 55 } 56 57 static int tunnel_key_parse_key_id(const char *str, int type, 58 struct nlmsghdr *n) 59 { 60 __be32 key_id; 61 int ret; 62 63 ret = get_be32(&key_id, str, 10); 64 if (!ret) 65 addattr32(n, MAX_MSG, type, key_id); 66 67 return ret; 68 } 69 70 static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n) 71 { 72 int ret; 73 __be16 dst_port; 74 75 ret = get_be16(&dst_port, str, 10); 76 if (ret) 77 return -1; 78 79 addattr16(n, MAX_MSG, type, dst_port); 80 81 return 0; 82 } 83 84 static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p, 85 int tca_id, struct nlmsghdr *n) 86 { 87 struct tc_tunnel_key parm = {}; 88 char **argv = *argv_p; 89 int argc = *argc_p; 90 struct rtattr *tail; 91 int action = 0; 92 int ret; 93 int has_src_ip = 0; 94 int has_dst_ip = 0; 95 int has_key_id = 0; 96 int csum = 1; 97 98 if (matches(*argv, "tunnel_key") != 0) 99 return -1; 100 101 tail = NLMSG_TAIL(n); 102 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 103 104 NEXT_ARG(); 105 106 while (argc > 0) { 107 if (matches(*argv, "unset") == 0) { 108 if (action) { 109 fprintf(stderr, "unexpected \"%s\" - action already specified\n", 110 *argv); 111 explain(); 112 return -1; 113 } 114 action = TCA_TUNNEL_KEY_ACT_RELEASE; 115 } else if (matches(*argv, "set") == 0) { 116 if (action) { 117 fprintf(stderr, "unexpected \"%s\" - action already specified\n", 118 *argv); 119 explain(); 120 return -1; 121 } 122 action = TCA_TUNNEL_KEY_ACT_SET; 123 } else if (matches(*argv, "src_ip") == 0) { 124 NEXT_ARG(); 125 ret = tunnel_key_parse_ip_addr(*argv, 126 TCA_TUNNEL_KEY_ENC_IPV4_SRC, 127 TCA_TUNNEL_KEY_ENC_IPV6_SRC, 128 n); 129 if (ret < 0) { 130 fprintf(stderr, "Illegal \"src_ip\"\n"); 131 return -1; 132 } 133 has_src_ip = 1; 134 } else if (matches(*argv, "dst_ip") == 0) { 135 NEXT_ARG(); 136 ret = tunnel_key_parse_ip_addr(*argv, 137 TCA_TUNNEL_KEY_ENC_IPV4_DST, 138 TCA_TUNNEL_KEY_ENC_IPV6_DST, 139 n); 140 if (ret < 0) { 141 fprintf(stderr, "Illegal \"dst_ip\"\n"); 142 return -1; 143 } 144 has_dst_ip = 1; 145 } else if (matches(*argv, "id") == 0) { 146 NEXT_ARG(); 147 ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n); 148 if (ret < 0) { 149 fprintf(stderr, "Illegal \"id\"\n"); 150 return -1; 151 } 152 has_key_id = 1; 153 } else if (matches(*argv, "dst_port") == 0) { 154 NEXT_ARG(); 155 ret = tunnel_key_parse_dst_port(*argv, 156 TCA_TUNNEL_KEY_ENC_DST_PORT, n); 157 if (ret < 0) { 158 fprintf(stderr, "Illegal \"dst port\"\n"); 159 return -1; 160 } 161 } else if (matches(*argv, "csum") == 0) { 162 csum = 1; 163 } else if (matches(*argv, "nocsum") == 0) { 164 csum = 0; 165 } else if (matches(*argv, "help") == 0) { 166 usage(); 167 } else { 168 break; 169 } 170 NEXT_ARG_FWD(); 171 } 172 173 addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum); 174 175 parse_action_control_dflt(&argc, &argv, &parm.action, 176 false, TC_ACT_PIPE); 177 178 if (argc) { 179 if (matches(*argv, "index") == 0) { 180 NEXT_ARG(); 181 if (get_u32(&parm.index, *argv, 10)) { 182 fprintf(stderr, "tunnel_key: Illegal \"index\"\n"); 183 return -1; 184 } 185 186 NEXT_ARG_FWD(); 187 } 188 } 189 190 if (action == TCA_TUNNEL_KEY_ACT_SET && 191 (!has_src_ip || !has_dst_ip || !has_key_id)) { 192 fprintf(stderr, "set needs tunnel_key parameters\n"); 193 explain(); 194 return -1; 195 } 196 197 parm.t_action = action; 198 addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm)); 199 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 200 201 *argc_p = argc; 202 *argv_p = argv; 203 204 return 0; 205 } 206 207 static void tunnel_key_print_ip_addr(FILE *f, const char *name, 208 struct rtattr *attr) 209 { 210 int family; 211 size_t len; 212 213 if (!attr) 214 return; 215 216 len = RTA_PAYLOAD(attr); 217 218 if (len == 4) 219 family = AF_INET; 220 else if (len == 16) 221 family = AF_INET6; 222 else 223 return; 224 225 fprintf(f, "\n\t%s %s", name, rt_addr_n2a_rta(family, attr)); 226 } 227 228 static void tunnel_key_print_key_id(FILE *f, const char *name, 229 struct rtattr *attr) 230 { 231 if (!attr) 232 return; 233 fprintf(f, "\n\t%s %d", name, rta_getattr_be32(attr)); 234 } 235 236 static void tunnel_key_print_dst_port(FILE *f, char *name, 237 struct rtattr *attr) 238 { 239 if (!attr) 240 return; 241 fprintf(f, "\n\t%s %d", name, rta_getattr_be16(attr)); 242 } 243 244 static void tunnel_key_print_flag(FILE *f, const char *name_on, 245 const char *name_off, 246 struct rtattr *attr) 247 { 248 if (!attr) 249 return; 250 fprintf(f, "\n\t%s", rta_getattr_u8(attr) ? name_on : name_off); 251 } 252 253 static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg) 254 { 255 struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1]; 256 struct tc_tunnel_key *parm; 257 258 if (!arg) 259 return -1; 260 261 parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg); 262 263 if (!tb[TCA_TUNNEL_KEY_PARMS]) { 264 fprintf(f, "[NULL tunnel_key parameters]"); 265 return -1; 266 } 267 parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]); 268 269 fprintf(f, "tunnel_key"); 270 271 switch (parm->t_action) { 272 case TCA_TUNNEL_KEY_ACT_RELEASE: 273 fprintf(f, " unset"); 274 break; 275 case TCA_TUNNEL_KEY_ACT_SET: 276 fprintf(f, " set"); 277 tunnel_key_print_ip_addr(f, "src_ip", 278 tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]); 279 tunnel_key_print_ip_addr(f, "dst_ip", 280 tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]); 281 tunnel_key_print_ip_addr(f, "src_ip", 282 tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]); 283 tunnel_key_print_ip_addr(f, "dst_ip", 284 tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]); 285 tunnel_key_print_key_id(f, "key_id", 286 tb[TCA_TUNNEL_KEY_ENC_KEY_ID]); 287 tunnel_key_print_dst_port(f, "dst_port", 288 tb[TCA_TUNNEL_KEY_ENC_DST_PORT]); 289 tunnel_key_print_flag(f, "nocsum", "csum", 290 tb[TCA_TUNNEL_KEY_NO_CSUM]); 291 break; 292 } 293 print_action_control(f, " ", parm->action, ""); 294 295 fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt, 296 parm->bindcnt); 297 298 if (show_stats) { 299 if (tb[TCA_TUNNEL_KEY_TM]) { 300 struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]); 301 302 print_tm(f, tm); 303 } 304 } 305 306 fprintf(f, "\n "); 307 308 return 0; 309 } 310 311 struct action_util tunnel_key_action_util = { 312 .id = "tunnel_key", 313 .parse_aopt = parse_tunnel_key, 314 .print_aopt = print_tunnel_key, 315 }; 316