1 /* 2 * ip.c "ip" utility frontend. 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 (at) ms2.inr.ac.ru> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <syslog.h> 16 #include <fcntl.h> 17 #include <sys/socket.h> 18 #include <netinet/in.h> 19 #include <string.h> 20 #include <errno.h> 21 22 #include "SNAPSHOT.h" 23 #include "utils.h" 24 #include "ip_common.h" 25 #include "namespace.h" 26 #include "color.h" 27 28 int preferred_family = AF_UNSPEC; 29 int human_readable; 30 int use_iec; 31 int show_stats; 32 int show_details; 33 int oneline; 34 int brief; 35 int json; 36 int timestamp; 37 const char *_SL_; 38 int force; 39 int max_flush_loops = 10; 40 int batch_mode; 41 bool do_all; 42 43 struct rtnl_handle rth = { .fd = -1 }; 44 45 static void usage(void) __attribute__((noreturn)); 46 47 static void usage(void) 48 { 49 fprintf(stderr, 50 "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" 51 " ip [ -force ] -batch filename\n" 52 "where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n" 53 " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" 54 " netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n" 55 " vrf | sr }\n" 56 " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" 57 " -h[uman-readable] | -iec |\n" 58 " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n" 59 " -4 | -6 | -I | -D | -B | -0 |\n" 60 " -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n" 61 " -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n" 62 " -rc[vbuf] [size] | -n[etns] name | -a[ll] |-c[olor]}\n"); 63 exit(-1); 64 } 65 66 static int do_help(int argc, char **argv) 67 { 68 usage(); 69 return 0; 70 } 71 72 static const struct cmd { 73 const char *cmd; 74 int (*func)(int argc, char **argv); 75 } cmds[] = { 76 { "address", do_ipaddr }, 77 { "addrlabel", do_ipaddrlabel }, 78 { "maddress", do_multiaddr }, 79 { "route", do_iproute }, 80 { "rule", do_iprule }, 81 { "neighbor", do_ipneigh }, 82 { "neighbour", do_ipneigh }, 83 { "ntable", do_ipntable }, 84 { "ntbl", do_ipntable }, 85 { "link", do_iplink }, 86 { "l2tp", do_ipl2tp }, 87 { "fou", do_ipfou }, 88 { "ila", do_ipila }, 89 { "macsec", do_ipmacsec }, 90 { "tunnel", do_iptunnel }, 91 { "tunl", do_iptunnel }, 92 { "tuntap", do_iptuntap }, 93 { "tap", do_iptuntap }, 94 { "token", do_iptoken }, 95 { "tcpmetrics", do_tcp_metrics }, 96 { "tcp_metrics", do_tcp_metrics }, 97 { "monitor", do_ipmonitor }, 98 { "xfrm", do_xfrm }, 99 { "mroute", do_multiroute }, 100 { "mrule", do_multirule }, 101 { "netns", do_netns }, 102 { "netconf", do_ipnetconf }, 103 { "vrf", do_ipvrf}, 104 { "sr", do_seg6 }, 105 { "help", do_help }, 106 { 0 } 107 }; 108 109 static int do_cmd(const char *argv0, int argc, char **argv) 110 { 111 const struct cmd *c; 112 113 for (c = cmds; c->cmd; ++c) { 114 if (matches(argv0, c->cmd) == 0) 115 return -(c->func(argc-1, argv+1)); 116 } 117 118 fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0); 119 return EXIT_FAILURE; 120 } 121 122 static int batch(const char *name) 123 { 124 char *line = NULL; 125 size_t len = 0; 126 int ret = EXIT_SUCCESS; 127 int orig_family = preferred_family; 128 129 batch_mode = 1; 130 131 if (name && strcmp(name, "-") != 0) { 132 if (freopen(name, "r", stdin) == NULL) { 133 fprintf(stderr, 134 "Cannot open file \"%s\" for reading: %s\n", 135 name, strerror(errno)); 136 return EXIT_FAILURE; 137 } 138 } 139 140 if (rtnl_open(&rth, 0) < 0) { 141 fprintf(stderr, "Cannot open rtnetlink\n"); 142 return EXIT_FAILURE; 143 } 144 145 cmdlineno = 0; 146 while (getcmdline(&line, &len, stdin) != -1) { 147 char *largv[100]; 148 int largc; 149 150 preferred_family = orig_family; 151 152 largc = makeargs(line, largv, 100); 153 if (largc == 0) 154 continue; /* blank line */ 155 156 if (do_cmd(largv[0], largc, largv)) { 157 fprintf(stderr, "Command failed %s:%d\n", 158 name, cmdlineno); 159 ret = EXIT_FAILURE; 160 if (!force) 161 break; 162 } 163 } 164 if (line) 165 free(line); 166 167 rtnl_close(&rth); 168 return ret; 169 } 170 171 172 int main(int argc, char **argv) 173 { 174 char *basename; 175 char *batch_file = NULL; 176 177 basename = strrchr(argv[0], '/'); 178 if (basename == NULL) 179 basename = argv[0]; 180 else 181 basename++; 182 183 while (argc > 1) { 184 char *opt = argv[1]; 185 186 if (strcmp(opt, "--") == 0) { 187 argc--; argv++; 188 break; 189 } 190 if (opt[0] != '-') 191 break; 192 if (opt[1] == '-') 193 opt++; 194 if (matches(opt, "-loops") == 0) { 195 argc--; 196 argv++; 197 if (argc <= 1) 198 usage(); 199 max_flush_loops = atoi(argv[1]); 200 } else if (matches(opt, "-family") == 0) { 201 argc--; 202 argv++; 203 if (argc <= 1) 204 usage(); 205 if (strcmp(argv[1], "help") == 0) 206 usage(); 207 else 208 preferred_family = read_family(argv[1]); 209 if (preferred_family == AF_UNSPEC) 210 invarg("invalid protocol family", argv[1]); 211 } else if (strcmp(opt, "-4") == 0) { 212 preferred_family = AF_INET; 213 } else if (strcmp(opt, "-6") == 0) { 214 preferred_family = AF_INET6; 215 } else if (strcmp(opt, "-0") == 0) { 216 preferred_family = AF_PACKET; 217 } else if (strcmp(opt, "-I") == 0) { 218 preferred_family = AF_IPX; 219 } else if (strcmp(opt, "-D") == 0) { 220 preferred_family = AF_DECnet; 221 } else if (strcmp(opt, "-M") == 0) { 222 preferred_family = AF_MPLS; 223 } else if (strcmp(opt, "-B") == 0) { 224 preferred_family = AF_BRIDGE; 225 } else if (matches(opt, "-human") == 0 || 226 matches(opt, "-human-readable") == 0) { 227 ++human_readable; 228 } else if (matches(opt, "-iec") == 0) { 229 ++use_iec; 230 } else if (matches(opt, "-stats") == 0 || 231 matches(opt, "-statistics") == 0) { 232 ++show_stats; 233 } else if (matches(opt, "-details") == 0) { 234 ++show_details; 235 } else if (matches(opt, "-resolve") == 0) { 236 ++resolve_hosts; 237 } else if (matches(opt, "-oneline") == 0) { 238 ++oneline; 239 } else if (matches(opt, "-timestamp") == 0) { 240 ++timestamp; 241 } else if (matches(opt, "-tshort") == 0) { 242 ++timestamp; 243 ++timestamp_short; 244 #if 0 245 } else if (matches(opt, "-numeric") == 0) { 246 rtnl_names_numeric++; 247 #endif 248 } else if (matches(opt, "-Version") == 0) { 249 printf("ip utility, iproute2-ss%s\n", SNAPSHOT); 250 exit(0); 251 } else if (matches(opt, "-force") == 0) { 252 ++force; 253 } else if (matches(opt, "-batch") == 0) { 254 argc--; 255 argv++; 256 if (argc <= 1) 257 usage(); 258 batch_file = argv[1]; 259 } else if (matches(opt, "-brief") == 0) { 260 ++brief; 261 } else if (matches(opt, "-json") == 0) { 262 ++json; 263 } else if (matches(opt, "-rcvbuf") == 0) { 264 unsigned int size; 265 266 argc--; 267 argv++; 268 if (argc <= 1) 269 usage(); 270 if (get_unsigned(&size, argv[1], 0)) { 271 fprintf(stderr, "Invalid rcvbuf size '%s'\n", 272 argv[1]); 273 exit(-1); 274 } 275 rcvbuf = size; 276 } else if (matches(opt, "-color") == 0) { 277 enable_color(); 278 } else if (matches(opt, "-help") == 0) { 279 usage(); 280 } else if (matches(opt, "-netns") == 0) { 281 NEXT_ARG(); 282 if (netns_switch(argv[1])) 283 exit(-1); 284 } else if (matches(opt, "-all") == 0) { 285 do_all = true; 286 } else { 287 fprintf(stderr, 288 "Option \"%s\" is unknown, try \"ip -help\".\n", 289 opt); 290 exit(-1); 291 } 292 argc--; argv++; 293 } 294 295 _SL_ = oneline ? "\\" : "\n"; 296 297 if (json) 298 check_if_color_enabled(); 299 300 if (batch_file) 301 return batch(batch_file); 302 303 if (rtnl_open(&rth, 0) < 0) 304 exit(1); 305 306 if (strlen(basename) > 2) 307 return do_cmd(basename+2, argc, argv); 308 309 if (argc > 1) 310 return do_cmd(argv[1], argc-1, argv+1); 311 312 rtnl_close(&rth); 313 usage(); 314 } 315