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 26 int preferred_family = AF_UNSPEC; 27 int show_stats = 0; 28 int show_details = 0; 29 int resolve_hosts = 0; 30 int oneline = 0; 31 int timestamp = 0; 32 char * _SL_ = NULL; 33 char *batch_file = NULL; 34 int force = 0; 35 struct rtnl_handle rth = { .fd = -1 }; 36 37 static void usage(void) __attribute__((noreturn)); 38 39 static void usage(void) 40 { 41 fprintf(stderr, 42 "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" 43 " ip [ -force ] -batch filename\n" 44 "where OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n" 45 " tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm }\n" 46 " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" 47 " -f[amily] { inet | inet6 | ipx | dnet | link } |\n" 48 " -o[neline] | -t[imestamp] | -b[atch] [filename] |\n" 49 " -rc[vbuf] [size]}\n"); 50 exit(-1); 51 } 52 53 static int do_help(int argc, char **argv) 54 { 55 usage(); 56 } 57 58 static const struct cmd { 59 const char *cmd; 60 int (*func)(int argc, char **argv); 61 } cmds[] = { 62 { "address", do_ipaddr }, 63 { "addrlabel", do_ipaddrlabel }, 64 { "maddress", do_multiaddr }, 65 { "route", do_iproute }, 66 { "rule", do_iprule }, 67 { "neighbor", do_ipneigh }, 68 { "neighbour", do_ipneigh }, 69 { "ntable", do_ipntable }, 70 { "ntbl", do_ipntable }, 71 { "link", do_iplink }, 72 { "tunnel", do_iptunnel }, 73 { "tunl", do_iptunnel }, 74 { "tuntap", do_iptuntap }, 75 { "tap", do_iptuntap }, 76 { "monitor", do_ipmonitor }, 77 { "xfrm", do_xfrm }, 78 { "mroute", do_multiroute }, 79 { "mrule", do_multirule }, 80 { "help", do_help }, 81 { 0, 0 } 82 }; 83 84 static int do_cmd(const char *argv0, int argc, char **argv) 85 { 86 const struct cmd *c; 87 88 for (c = cmds; c->cmd; ++c) { 89 if (matches(argv0, c->cmd) == 0) 90 return c->func(argc-1, argv+1); 91 } 92 93 fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0); 94 return -1; 95 } 96 97 #ifndef ANDROID 98 static int batch(const char *name) 99 { 100 char *line = NULL; 101 size_t len = 0; 102 int ret = 0; 103 104 if (name && strcmp(name, "-") != 0) { 105 if (freopen(name, "r", stdin) == NULL) { 106 fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n", 107 name, strerror(errno)); 108 return -1; 109 } 110 } 111 112 if (rtnl_open(&rth, 0) < 0) { 113 fprintf(stderr, "Cannot open rtnetlink\n"); 114 return -1; 115 } 116 117 cmdlineno = 0; 118 while (getcmdline(&line, &len, stdin) != -1) { 119 char *largv[100]; 120 int largc; 121 122 largc = makeargs(line, largv, 100); 123 if (largc == 0) 124 continue; /* blank line */ 125 126 if (do_cmd(largv[0], largc, largv)) { 127 fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno); 128 ret = 1; 129 if (!force) 130 break; 131 } 132 } 133 if (line) 134 free(line); 135 136 rtnl_close(&rth); 137 return ret; 138 } 139 #endif 140 141 int main(int argc, char **argv) 142 { 143 char *basename; 144 145 basename = strrchr(argv[0], '/'); 146 if (basename == NULL) 147 basename = argv[0]; 148 else 149 basename++; 150 151 while (argc > 1) { 152 char *opt = argv[1]; 153 if (strcmp(opt,"--") == 0) { 154 argc--; argv++; 155 break; 156 } 157 if (opt[0] != '-') 158 break; 159 if (opt[1] == '-') 160 opt++; 161 if (matches(opt, "-family") == 0) { 162 argc--; 163 argv++; 164 if (argc <= 1) 165 usage(); 166 if (strcmp(argv[1], "inet") == 0) 167 preferred_family = AF_INET; 168 else if (strcmp(argv[1], "inet6") == 0) 169 preferred_family = AF_INET6; 170 else if (strcmp(argv[1], "dnet") == 0) 171 preferred_family = AF_DECnet; 172 else if (strcmp(argv[1], "link") == 0) 173 preferred_family = AF_PACKET; 174 else if (strcmp(argv[1], "ipx") == 0) 175 preferred_family = AF_IPX; 176 else if (strcmp(argv[1], "help") == 0) 177 usage(); 178 else 179 invarg(argv[1], "invalid protocol family"); 180 } else if (strcmp(opt, "-4") == 0) { 181 preferred_family = AF_INET; 182 } else if (strcmp(opt, "-6") == 0) { 183 preferred_family = AF_INET6; 184 } else if (strcmp(opt, "-0") == 0) { 185 preferred_family = AF_PACKET; 186 } else if (strcmp(opt, "-I") == 0) { 187 preferred_family = AF_IPX; 188 } else if (strcmp(opt, "-D") == 0) { 189 preferred_family = AF_DECnet; 190 } else if (matches(opt, "-stats") == 0 || 191 matches(opt, "-statistics") == 0) { 192 ++show_stats; 193 } else if (matches(opt, "-details") == 0) { 194 ++show_details; 195 } else if (matches(opt, "-resolve") == 0) { 196 ++resolve_hosts; 197 } else if (matches(opt, "-oneline") == 0) { 198 ++oneline; 199 } else if (matches(opt, "-timestamp") == 0) { 200 ++timestamp; 201 #if 0 202 } else if (matches(opt, "-numeric") == 0) { 203 rtnl_names_numeric++; 204 #endif 205 } else if (matches(opt, "-Version") == 0) { 206 printf("ip utility, iproute2-ss%s\n", SNAPSHOT); 207 exit(0); 208 } else if (matches(opt, "-force") == 0) { 209 ++force; 210 #ifndef ANDROID 211 } else if (matches(opt, "-batch") == 0) { 212 argc--; 213 argv++; 214 if (argc <= 1) 215 usage(); 216 batch_file = argv[1]; 217 #endif 218 } else if (matches(opt, "-rcvbuf") == 0) { 219 unsigned int size; 220 221 argc--; 222 argv++; 223 if (argc <= 1) 224 usage(); 225 if (get_unsigned(&size, argv[1], 0)) { 226 fprintf(stderr, "Invalid rcvbuf size '%s'\n", 227 argv[1]); 228 exit(-1); 229 } 230 rcvbuf = size; 231 } else if (matches(opt, "-help") == 0) { 232 usage(); 233 } else { 234 fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt); 235 exit(-1); 236 } 237 argc--; argv++; 238 } 239 240 _SL_ = oneline ? "\\" : "\n" ; 241 242 #ifndef ANDROID 243 if (batch_file) 244 return batch(batch_file); 245 #endif 246 247 if (rtnl_open(&rth, 0) < 0) 248 exit(1); 249 250 if (strlen(basename) > 2) 251 return do_cmd(basename+2, argc, argv); 252 253 if (argc > 1) 254 return do_cmd(argv[1], argc-1, argv+1); 255 256 rtnl_close(&rth); 257 usage(); 258 } 259