aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
Diffstat (limited to 'networking')
-rw-r--r--networking/Makefile.in1
-rw-r--r--networking/config.in7
-rw-r--r--networking/ifconfig.c67
-rw-r--r--networking/netstat.c122
-rw-r--r--networking/ping6.c515
-rw-r--r--networking/route.c243
6 files changed, 947 insertions, 8 deletions
diff --git a/networking/Makefile.in b/networking/Makefile.in
index 6f3cc2189..be4b53b78 100644
--- a/networking/Makefile.in
+++ b/networking/Makefile.in
@@ -29,6 +29,7 @@ NETWORKING-$(CONFIG_NC) += nc.o
29NETWORKING-$(CONFIG_NETSTAT) += netstat.o 29NETWORKING-$(CONFIG_NETSTAT) += netstat.o
30NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o 30NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o
31NETWORKING-$(CONFIG_PING) += ping.o 31NETWORKING-$(CONFIG_PING) += ping.o
32NETWORKING-$(CONFIG_PING6) += ping6.o
32NETWORKING-$(CONFIG_ROUTE) += route.o 33NETWORKING-$(CONFIG_ROUTE) += route.o
33NETWORKING-$(CONFIG_TELNET) += telnet.o 34NETWORKING-$(CONFIG_TELNET) += telnet.o
34NETWORKING-$(CONFIG_TFTP) += tftp.o 35NETWORKING-$(CONFIG_TFTP) += tftp.o
diff --git a/networking/config.in b/networking/config.in
index b148eb57c..1edc1de7e 100644
--- a/networking/config.in
+++ b/networking/config.in
@@ -6,6 +6,7 @@
6mainmenu_option next_comment 6mainmenu_option next_comment
7comment 'Networking Utilities' 7comment 'Networking Utilities'
8 8
9bool 'Enable IPv6 support' CONFIG_FEATURE_IPV6
9bool 'hostname' CONFIG_HOSTNAME 10bool 'hostname' CONFIG_HOSTNAME
10bool 'ifconfig' CONFIG_IFCONFIG 11bool 'ifconfig' CONFIG_IFCONFIG
11if [ "$CONFIG_IFCONFIG" = "y" ]; then 12if [ "$CONFIG_IFCONFIG" = "y" ]; then
@@ -22,6 +23,12 @@ bool 'ping' CONFIG_PING
22if [ "$CONFIG_PING" = "y" ]; then 23if [ "$CONFIG_PING" = "y" ]; then
23 bool ' Enable fancy ping output' CONFIG_FEATURE_FANCY_PING 24 bool ' Enable fancy ping output' CONFIG_FEATURE_FANCY_PING
24fi 25fi
26if [ "$CONFIG_FEATURE_IPV6" = "y" ]; then
27 bool 'ping6' CONFIG_PING6
28 if [ "$CONFIG_PING6" = "y" ]; then
29 bool ' Enable fancy ping6 output' CONFIG_FEATURE_FANCY_PING6
30 fi
31fi
25bool 'route' CONFIG_ROUTE 32bool 'route' CONFIG_ROUTE
26bool 'telnet' CONFIG_TELNET 33bool 'telnet' CONFIG_TELNET
27if [ "$CONFIG_TELNET" = "y" ]; then 34if [ "$CONFIG_TELNET" = "y" ]; then
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 0b834e7c7..9e87c8be5 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -15,7 +15,7 @@
15 * Foundation; either version 2 of the License, or (at 15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version. 16 * your option) any later version.
17 * 17 *
18 * $Id: ifconfig.c,v 1.16 2001/11/10 11:22:43 andersen Exp $ 18 * $Id: ifconfig.c,v 1.17 2002/07/03 11:46:34 andersen Exp $
19 * 19 *
20 */ 20 */
21 21
@@ -27,6 +27,9 @@
27 * args missing from initial port. 27 * args missing from initial port.
28 * 28 *
29 * Still missing: media, tunnel. 29 * Still missing: media, tunnel.
30 *
31 * 2002-04-20
32 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
30 */ 33 */
31 34
32#include <stdio.h> 35#include <stdio.h>
@@ -65,6 +68,14 @@
65#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ 68#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
66#endif 69#endif
67 70
71#if CONFIG_FEATURE_IPV6
72struct in6_ifreq {
73 struct in6_addr ifr6_addr;
74 uint32_t ifr6_prefixlen;
75 int ifr6_ifindex;
76};
77#endif
78
68/* 79/*
69 * Here are the bit masks for the "flags" member of struct options below. 80 * Here are the bit masks for the "flags" member of struct options below.
70 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. 81 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
@@ -143,6 +154,7 @@
143#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR) 154#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
144#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR) 155#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
145#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK) 156#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
157#define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
146 158
147 159
148/* 160/*
@@ -187,6 +199,10 @@ static const struct arg1opt Arg1Opt[] = {
187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, 199 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
188#endif 200#endif
189 /* Last entry if for unmatched (possibly hostname) arg. */ 201 /* Last entry if for unmatched (possibly hostname) arg. */
202#if CONFIG_FEATURE_IPV6
203 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
204 {"SIOCDIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
205#endif
190 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, 206 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
191}; 207};
192 208
@@ -212,6 +228,10 @@ static const struct options OptArray[] = {
212 {"io_addr", N_ARG, ARG_IO_ADDR, 0}, 228 {"io_addr", N_ARG, ARG_IO_ADDR, 0},
213 {"irq", N_ARG, ARG_IRQ, 0}, 229 {"irq", N_ARG, ARG_IRQ, 0},
214#endif 230#endif
231#if CONFIG_FEATURE_IPV6
232 {"add", N_ARG, ARG_ADD_DEL, 0},
233 {"del", N_ARG, ARG_ADD_DEL, 0},
234#endif
215 {"arp", N_CLR | M_SET, 0, IFF_NOARP}, 235 {"arp", N_CLR | M_SET, 0, IFF_NOARP},
216 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS}, 236 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
217 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC}, 237 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
@@ -244,6 +264,9 @@ int ifconfig_main(int argc, char **argv)
244{ 264{
245 struct ifreq ifr; 265 struct ifreq ifr;
246 struct sockaddr_in sai; 266 struct sockaddr_in sai;
267#if CONFIG_FEATURE_IPV6
268 struct sockaddr_in6 sai6;
269#endif
247#ifdef CONFIG_FEATURE_IFCONFIG_HW 270#ifdef CONFIG_FEATURE_IFCONFIG_HW
248 struct sockaddr sa; 271 struct sockaddr sa;
249#endif 272#endif
@@ -334,12 +357,54 @@ int ifconfig_main(int argc, char **argv)
334#ifdef CONFIG_FEATURE_IFCONFIG_HW 357#ifdef CONFIG_FEATURE_IFCONFIG_HW
335 if (mask & A_CAST_RESOLVE) { 358 if (mask & A_CAST_RESOLVE) {
336#endif 359#endif
360#if CONFIG_FEATURE_IPV6
361 char *prefix;
362 int prefix_len=0;
363#endif
364
337 safe_strncpy(host, *argv, (sizeof host)); 365 safe_strncpy(host, *argv, (sizeof host));
366#if CONFIG_FEATURE_IPV6
367 if ((prefix = strchr(host, '/'))) {
368 prefix_len = atol(prefix + 1);
369 if ((prefix_len < 0) || (prefix_len > 128)) {
370 ++goterr;
371 goto LOOP;
372 }
373 *prefix = 0;
374 }
375#endif
376
338 sai.sin_family = AF_INET; 377 sai.sin_family = AF_INET;
339 sai.sin_port = 0; 378 sai.sin_port = 0;
340 if (!strcmp(host, bb_INET_default)) { 379 if (!strcmp(host, bb_INET_default)) {
341 /* Default is special, meaning 0.0.0.0. */ 380 /* Default is special, meaning 0.0.0.0. */
342 sai.sin_addr.s_addr = INADDR_ANY; 381 sai.sin_addr.s_addr = INADDR_ANY;
382#if CONFIG_FEATURE_IPV6
383 } else
384 if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) {
385 int sockfd6;
386 struct in6_ifreq ifr6;
387
388 memcpy((char *) &ifr6.ifr6_addr, (char *) &sai6.sin6_addr,
389 sizeof(struct in6_addr));
390
391 /* Create a channel to the NET kernel. */
392 if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
393 perror_msg_and_die("socket6");
394 }
395 if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) {
396 perror("SIOGIFINDEX");
397 ++goterr;
398 continue;
399 }
400 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
401 ifr6.ifr6_prefixlen = prefix_len;
402 if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) {
403 perror(a1op->name);
404 ++goterr;
405 }
406 continue;
407#endif
343 } else if (inet_aton(host, &sai.sin_addr) == 0) { 408 } else if (inet_aton(host, &sai.sin_addr) == 0) {
344 /* It's not a dotted quad. */ 409 /* It's not a dotted quad. */
345 ++goterr; 410 ++goterr;
diff --git a/networking/netstat.c b/networking/netstat.c
index 00b58228e..67ecc0105 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -3,7 +3,7 @@
3 * Mini netstat implementation(s) for busybox 3 * Mini netstat implementation(s) for busybox
4 * based in part on the netstat implementation from net-tools. 4 * based in part on the netstat implementation from net-tools.
5 * 5 *
6 * Copyright (C) 2001 by Bart Visscher <magick@linux-fan.com> 6 * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -18,6 +18,9 @@
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * 2002-04-20
23 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
21 */ 24 */
22 25
23#include <stdio.h> 26#include <stdio.h>
@@ -128,9 +131,17 @@ static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int
128{ 131{
129 char *port_name; 132 char *port_name;
130 133
134#if CONFIG_FEATURE_IPV6
135 if (addr->sa_family == AF_INET6) {
136 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
137 (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
138 } else
139#endif
140 {
131 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr, 141 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
132 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0), 142 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
133 0xffffffff); 143 0xffffffff);
144 }
134 port_name=get_sname(htons(port), proto, numeric); 145 port_name=get_sname(htons(port), proto, numeric);
135 if ((strlen(ip_port) + strlen(port_name)) > 22) 146 if ((strlen(ip_port) + strlen(port_name)) > 22)
136 ip_port[22 - strlen(port_name)] = '\0'; 147 ip_port[22 - strlen(port_name)] = '\0';
@@ -145,7 +156,13 @@ static void tcp_do_one(int lnr, const char *line)
145 const char *state_str; 156 const char *state_str;
146 char more[512]; 157 char more[512];
147 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 158 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
159#if CONFIG_FEATURE_IPV6
160 struct sockaddr_in6 localaddr, remaddr;
161 char addr6[INET6_ADDRSTRLEN];
162 struct in6_addr in6;
163#else
148 struct sockaddr_in localaddr, remaddr; 164 struct sockaddr_in localaddr, remaddr;
165#endif
149 unsigned long rxq, txq, time_len, retr, inode; 166 unsigned long rxq, txq, time_len, retr, inode;
150 167
151 if (lnr == 0) 168 if (lnr == 0)
@@ -159,6 +176,20 @@ static void tcp_do_one(int lnr, const char *line)
159 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 176 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
160 177
161 if (strlen(local_addr) > 8) { 178 if (strlen(local_addr) > 8) {
179#if CONFIG_FEATURE_IPV6
180 sscanf(local_addr, "%08X%08X%08X%08X",
181 &in6.s6_addr32[0], &in6.s6_addr32[1],
182 &in6.s6_addr32[2], &in6.s6_addr32[3]);
183 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
184 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
185 sscanf(rem_addr, "%08X%08X%08X%08X",
186 &in6.s6_addr32[0], &in6.s6_addr32[1],
187 &in6.s6_addr32[2], &in6.s6_addr32[3]);
188 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
189 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
190 localaddr.sin6_family = AF_INET6;
191 remaddr.sin6_family = AF_INET6;
192#endif
162 } else { 193 } else {
163 sscanf(local_addr, "%X", 194 sscanf(local_addr, "%X",
164 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 195 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
@@ -195,7 +226,13 @@ static void udp_do_one(int lnr, const char *line)
195 char local_addr[64], rem_addr[64]; 226 char local_addr[64], rem_addr[64];
196 char *state_str, more[512]; 227 char *state_str, more[512];
197 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 228 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
229#if CONFIG_FEATURE_IPV6
230 struct sockaddr_in6 localaddr, remaddr;
231 char addr6[INET6_ADDRSTRLEN];
232 struct in6_addr in6;
233#else
198 struct sockaddr_in localaddr, remaddr; 234 struct sockaddr_in localaddr, remaddr;
235#endif
199 unsigned long rxq, txq, time_len, retr, inode; 236 unsigned long rxq, txq, time_len, retr, inode;
200 237
201 if (lnr == 0) 238 if (lnr == 0)
@@ -209,6 +246,21 @@ static void udp_do_one(int lnr, const char *line)
209 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 246 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
210 247
211 if (strlen(local_addr) > 8) { 248 if (strlen(local_addr) > 8) {
249#if CONFIG_FEATURE_IPV6
250 /* Demangle what the kernel gives us */
251 sscanf(local_addr, "%08X%08X%08X%08X",
252 &in6.s6_addr32[0], &in6.s6_addr32[1],
253 &in6.s6_addr32[2], &in6.s6_addr32[3]);
254 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
255 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
256 sscanf(rem_addr, "%08X%08X%08X%08X",
257 &in6.s6_addr32[0], &in6.s6_addr32[1],
258 &in6.s6_addr32[2], &in6.s6_addr32[3]);
259 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
260 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
261 localaddr.sin6_family = AF_INET6;
262 remaddr.sin6_family = AF_INET6;
263#endif
212 } else { 264 } else {
213 sscanf(local_addr, "%X", 265 sscanf(local_addr, "%X",
214 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 266 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
@@ -236,7 +288,17 @@ static void udp_do_one(int lnr, const char *line)
236 break; 288 break;
237 } 289 }
238 290
291#if CONFIG_FEATURE_IPV6
292#define notnull(A) (((A.sin6_family == AF_INET6) && \
293 ((A.sin6_addr.s6_addr32[0]) || \
294 (A.sin6_addr.s6_addr32[1]) || \
295 (A.sin6_addr.s6_addr32[2]) || \
296 (A.sin6_addr.s6_addr32[3]))) || \
297 ((A.sin6_family == AF_INET) && \
298 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
299#else
239#define notnull(A) (A.sin_addr.s_addr) 300#define notnull(A) (A.sin_addr.s_addr)
301#endif
240 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || 302 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
241 (!notnull(remaddr) && (flags&NETSTAT_LISTENING))) 303 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
242 { 304 {
@@ -259,7 +321,13 @@ static void raw_do_one(int lnr, const char *line)
259 char local_addr[64], rem_addr[64]; 321 char local_addr[64], rem_addr[64];
260 char *state_str, more[512]; 322 char *state_str, more[512];
261 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 323 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
324#if CONFIG_FEATURE_IPV6
325 struct sockaddr_in6 localaddr, remaddr;
326 char addr6[INET6_ADDRSTRLEN];
327 struct in6_addr in6;
328#else
262 struct sockaddr_in localaddr, remaddr; 329 struct sockaddr_in localaddr, remaddr;
330#endif
263 unsigned long rxq, txq, time_len, retr, inode; 331 unsigned long rxq, txq, time_len, retr, inode;
264 332
265 if (lnr == 0) 333 if (lnr == 0)
@@ -273,6 +341,20 @@ static void raw_do_one(int lnr, const char *line)
273 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 341 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
274 342
275 if (strlen(local_addr) > 8) { 343 if (strlen(local_addr) > 8) {
344#if CONFIG_FEATURE_IPV6
345 sscanf(local_addr, "%08X%08X%08X%08X",
346 &in6.s6_addr32[0], &in6.s6_addr32[1],
347 &in6.s6_addr32[2], &in6.s6_addr32[3]);
348 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
349 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
350 sscanf(rem_addr, "%08X%08X%08X%08X",
351 &in6.s6_addr32[0], &in6.s6_addr32[1],
352 &in6.s6_addr32[2], &in6.s6_addr32[3]);
353 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
354 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
355 localaddr.sin6_family = AF_INET6;
356 remaddr.sin6_family = AF_INET6;
357#endif
276 } else { 358 } else {
277 sscanf(local_addr, "%X", 359 sscanf(local_addr, "%X",
278 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 360 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
@@ -288,7 +370,17 @@ static void raw_do_one(int lnr, const char *line)
288 } 370 }
289 state_str=itoa(state); 371 state_str=itoa(state);
290 372
373#if CONFIG_FEATURE_IPV6
374#define notnull(A) (((A.sin6_family == AF_INET6) && \
375 ((A.sin6_addr.s6_addr32[0]) || \
376 (A.sin6_addr.s6_addr32[1]) || \
377 (A.sin6_addr.s6_addr32[2]) || \
378 (A.sin6_addr.s6_addr32[3]))) || \
379 ((A.sin6_family == AF_INET) && \
380 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
381#else
291#define notnull(A) (A.sin_addr.s_addr) 382#define notnull(A) (A.sin_addr.s_addr)
383#endif
292 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || 384 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
293 (!notnull(remaddr) && (flags&NETSTAT_LISTENING))) 385 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
294 { 386 {
@@ -429,8 +521,11 @@ static void unix_do_one(int nr, const char *line)
429} 521}
430 522
431#define _PATH_PROCNET_UDP "/proc/net/udp" 523#define _PATH_PROCNET_UDP "/proc/net/udp"
524#define _PATH_PROCNET_UDP6 "/proc/net/udp6"
432#define _PATH_PROCNET_TCP "/proc/net/tcp" 525#define _PATH_PROCNET_TCP "/proc/net/tcp"
526#define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
433#define _PATH_PROCNET_RAW "/proc/net/raw" 527#define _PATH_PROCNET_RAW "/proc/net/raw"
528#define _PATH_PROCNET_RAW6 "/proc/net/raw6"
434#define _PATH_PROCNET_UNIX "/proc/net/unix" 529#define _PATH_PROCNET_UNIX "/proc/net/unix"
435 530
436static void do_info(const char *file, const char *name, void (*proc)(int, const char *)) 531static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
@@ -464,6 +559,13 @@ int netstat_main(int argc, char **argv)
464 int opt; 559 int opt;
465 int new_flags=0; 560 int new_flags=0;
466 int showroute = 0, extended = 0; 561 int showroute = 0, extended = 0;
562#if CONFIG_FEATURE_IPV6
563 int inet=1;
564 int inet6=1;
565#else
566#define inet 1
567#define inet6 0
568#endif
467 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1) 569 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
468 switch (opt) { 570 switch (opt) {
469 case 'l': 571 case 'l':
@@ -523,12 +625,24 @@ int netstat_main(int argc, char **argv)
523 } 625 }
524 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n"); 626 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
525 } 627 }
526 if (flags&NETSTAT_TCP) 628 if (inet && flags&NETSTAT_TCP)
527 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one); 629 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
528 if (flags&NETSTAT_UDP) 630#if CONFIG_FEATURE_IPV6
631 if (inet6 && flags&NETSTAT_TCP)
632 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
633#endif
634 if (inet && flags&NETSTAT_UDP)
529 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one); 635 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
530 if (flags&NETSTAT_RAW) 636#if CONFIG_FEATURE_IPV6
637 if (inet6 && flags&NETSTAT_UDP)
638 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
639#endif
640 if (inet && flags&NETSTAT_RAW)
531 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one); 641 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
642#if CONFIG_FEATURE_IPV6
643 if (inet6 && flags&NETSTAT_RAW)
644 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
645#endif
532 if (flags&NETSTAT_UNIX) { 646 if (flags&NETSTAT_UNIX) {
533 printf("Active UNIX domain sockets "); 647 printf("Active UNIX domain sockets ");
534 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED)) 648 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
diff --git a/networking/ping6.c b/networking/ping6.c
new file mode 100644
index 000000000..bff700c0e
--- /dev/null
+++ b/networking/ping6.c
@@ -0,0 +1,515 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * $Id: ping6.c,v 1.1 2002/07/03 11:46:34 andersen Exp $
4 * Mini ping implementation for busybox
5 *
6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * This version of ping is adapted from the ping in netkit-base 0.10,
23 * which is:
24 *
25 * Copyright (c) 1989 The Regents of the University of California.
26 * All rights reserved.
27 *
28 * This code is derived from software contributed to Berkeley by
29 * Mike Muuss.
30 *
31 * Original copyright notice is retained at the end of this file.
32 *
33 * This version is an adaptation of ping.c from busybox.
34 * The code was modified by Bart Visscher <magick@linux-fan.com>
35 */
36
37#include <sys/param.h>
38#include <sys/socket.h>
39#include <sys/file.h>
40#include <sys/time.h>
41#include <sys/times.h>
42#include <sys/signal.h>
43
44#include <netinet/in.h>
45#include <netinet/ip6.h>
46#include <netinet/icmp6.h>
47#include <arpa/inet.h>
48#include <net/if.h>
49#include <netdb.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <errno.h>
53#include <unistd.h>
54#include <string.h>
55#include <stdlib.h>
56#include <stddef.h> /* offsetof */
57#include "busybox.h"
58
59static const int DEFDATALEN = 56;
60static const int MAXIPLEN = 60;
61static const int MAXICMPLEN = 76;
62static const int MAXPACKET = 65468;
63#define MAX_DUP_CHK (8 * 128)
64static const int MAXWAIT = 10;
65static const int PINGINTERVAL = 1; /* second */
66
67#define O_QUIET (1 << 0)
68#define O_VERBOSE (1 << 1)
69
70#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
71#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
72#define SET(bit) (A(bit) |= B(bit))
73#define CLR(bit) (A(bit) &= (~B(bit)))
74#define TST(bit) (A(bit) & B(bit))
75
76static void ping(const char *host);
77
78/* simple version */
79#ifndef CONFIG_FEATURE_FANCY_PING6
80
81static void ping(const char *host)
82{
83 struct hostent *h;
84 struct sockaddr_in6 pingaddr;
85 struct icmp6_hdr *pkt;
86 int pingsock, c;
87 int sockopt;
88 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
89
90 void noresp(int ign)
91 {
92 printf("No response from %s\n", h->h_name);
93 exit(0);
94 }
95
96 pingsock = create_icmp6_socket();
97
98 memset(&pingaddr, 0, sizeof(struct sockaddr_in));
99
100 pingaddr.sin6_family = AF_INET6;
101 h = xgethostbyname2(host, AF_INET6);
102 memcpy(&pingaddr.sin6_addr, h->h_addr, sizeof(pingaddr.sin6_addr));
103
104 pkt = (struct icmp6_hdr *) packet;
105 memset(pkt, 0, sizeof(packet));
106 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
107
108 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
109 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt,
110 sizeof(sockopt));
111
112 c = sendto(pingsock, packet, sizeof(packet), 0,
113 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6));
114
115 if (c < 0 || c != sizeof(packet))
116 perror_msg_and_die("sendto");
117
118 signal(SIGALRM, noresp);
119 alarm(5); /* give the host 5000ms to respond */
120 /* listen for replies */
121 while (1) {
122 struct sockaddr_in6 from;
123 size_t fromlen = sizeof(from);
124
125 if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
126 (struct sockaddr *) &from, &fromlen)) < 0) {
127 if (errno == EINTR)
128 continue;
129 perror_msg("recvfrom");
130 continue;
131 }
132 if (c >= 8) { /* icmp6_hdr */
133 pkt = (struct icmp6_hdr *) packet;
134 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
135 break;
136 }
137 }
138 printf("%s is alive!\n", h->h_name);
139 return;
140}
141
142extern int ping6_main(int argc, char **argv)
143{
144 argc--;
145 argv++;
146 if (argc < 1)
147 show_usage();
148 ping(*argv);
149 return EXIT_SUCCESS;
150}
151
152#else /* ! CONFIG_FEATURE_FANCY_PING6 */
153/* full(er) version */
154static struct sockaddr_in6 pingaddr;
155static int pingsock = -1;
156static int datalen; /* intentionally uninitialized to work around gcc bug */
157static char* ifname;
158
159static long ntransmitted, nreceived, nrepeats, pingcount;
160static int myid, options;
161static unsigned long tmin = ULONG_MAX, tmax, tsum;
162static char rcvd_tbl[MAX_DUP_CHK / 8];
163
164#if CONFIG_FEATURE_FANCY_PING
165extern
166#endif
167 struct hostent *hostent;
168
169static void sendping(int);
170static void pingstats(int);
171static void unpack(char *, int, struct sockaddr_in6 *, int);
172
173/**************************************************************************/
174
175static void pingstats(int junk)
176{
177 int status;
178
179 signal(SIGINT, SIG_IGN);
180
181 printf("\n--- %s ping statistics ---\n", hostent->h_name);
182 printf("%ld packets transmitted, ", ntransmitted);
183 printf("%ld packets received, ", nreceived);
184 if (nrepeats)
185 printf("%ld duplicates, ", nrepeats);
186 if (ntransmitted)
187 printf("%ld%% packet loss\n",
188 (ntransmitted - nreceived) * 100 / ntransmitted);
189 if (nreceived)
190 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
191 tmin / 10, tmin % 10,
192 (tsum / (nreceived + nrepeats)) / 10,
193 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
194 if (nreceived != 0)
195 status = EXIT_SUCCESS;
196 else
197 status = EXIT_FAILURE;
198 exit(status);
199}
200
201static void sendping(int junk)
202{
203 struct icmp6_hdr *pkt;
204 int i;
205 char packet[datalen + 8];
206
207 pkt = (struct icmp6_hdr *) packet;
208
209 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
210 pkt->icmp6_code = 0;
211 pkt->icmp6_cksum = 0;
212 pkt->icmp6_seq = ntransmitted++;
213 pkt->icmp6_id = myid;
214 CLR(pkt->icmp6_seq % MAX_DUP_CHK);
215
216 gettimeofday((struct timeval *) &pkt->icmp6_data8[4], NULL);
217
218 i = sendto(pingsock, packet, sizeof(packet), 0,
219 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6));
220
221 if (i < 0)
222 perror_msg_and_die("sendto");
223 else if ((size_t)i != sizeof(packet))
224 error_msg_and_die("ping wrote %d chars; %d expected", i,
225 (int)sizeof(packet));
226
227 signal(SIGALRM, sendping);
228 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
229 alarm(PINGINTERVAL);
230 } else { /* done, wait for the last ping to come back */
231 /* todo, don't necessarily need to wait so long... */
232 signal(SIGALRM, pingstats);
233 alarm(MAXWAIT);
234 }
235}
236
237static char *icmp6_type_name (int id)
238{
239 switch (id) {
240 case ICMP6_DST_UNREACH: return "Destination Unreachable";
241 case ICMP6_PACKET_TOO_BIG: return "Packet too big";
242 case ICMP6_TIME_EXCEEDED: return "Time Exceeded";
243 case ICMP6_PARAM_PROB: return "Parameter Problem";
244 case ICMP6_ECHO_REPLY: return "Echo Reply";
245 case ICMP6_ECHO_REQUEST: return "Echo Request";
246 case ICMP6_MEMBERSHIP_QUERY: return "Membership Query";
247 case ICMP6_MEMBERSHIP_REPORT: return "Membership Report";
248 case ICMP6_MEMBERSHIP_REDUCTION: return "Membership Reduction";
249 default: return "unknown ICMP type";
250 }
251}
252
253static void unpack(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
254{
255 struct icmp6_hdr *icmppkt;
256 struct timeval tv, *tp;
257 int dupflag;
258 unsigned long triptime;
259 char buf[INET6_ADDRSTRLEN];
260
261 gettimeofday(&tv, NULL);
262
263 /* discard if too short */
264 if (sz < (datalen + sizeof(struct icmp6_hdr)))
265 return;
266
267 icmppkt = (struct icmp6_hdr *) packet;
268
269 if (icmppkt->icmp6_id != myid)
270 return; /* not our ping */
271
272 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
273 ++nreceived;
274 tp = (struct timeval *) &icmppkt->icmp6_data8[4];
275
276 if ((tv.tv_usec -= tp->tv_usec) < 0) {
277 --tv.tv_sec;
278 tv.tv_usec += 1000000;
279 }
280 tv.tv_sec -= tp->tv_sec;
281
282 triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
283 tsum += triptime;
284 if (triptime < tmin)
285 tmin = triptime;
286 if (triptime > tmax)
287 tmax = triptime;
288
289 if (TST(icmppkt->icmp6_seq % MAX_DUP_CHK)) {
290 ++nrepeats;
291 --nreceived;
292 dupflag = 1;
293 } else {
294 SET(icmppkt->icmp6_seq % MAX_DUP_CHK);
295 dupflag = 0;
296 }
297
298 if (options & O_QUIET)
299 return;
300
301 printf("%d bytes from %s: icmp6_seq=%u", sz,
302 inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr,
303 buf, sizeof(buf)),
304 icmppkt->icmp6_seq);
305 printf(" ttl=%d time=%lu.%lu ms", hoplimit,
306 triptime / 10, triptime % 10);
307 if (dupflag)
308 printf(" (DUP!)");
309 printf("\n");
310 } else
311 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST)
312 error_msg("Warning: Got ICMP %d (%s)",
313 icmppkt->icmp6_type, icmp6_type_name (icmppkt->icmp6_type));
314}
315
316static void ping(const char *host)
317{
318 char packet[datalen + MAXIPLEN + MAXICMPLEN];
319 char buf[INET6_ADDRSTRLEN];
320 int sockopt;
321 struct msghdr msg;
322 struct sockaddr_in6 from;
323 struct iovec iov;
324 char control_buf[CMSG_SPACE(36)];
325
326 pingsock = create_icmp6_socket();
327
328 memset(&pingaddr, 0, sizeof(struct sockaddr_in));
329
330 pingaddr.sin6_family = AF_INET6;
331 hostent = xgethostbyname2(host, AF_INET6);
332 if (hostent->h_addrtype != AF_INET6)
333 error_msg_and_die("unknown address type; only AF_INET6 is currently supported.");
334
335 memcpy(&pingaddr.sin6_addr, hostent->h_addr, sizeof(pingaddr.sin6_addr));
336
337#ifdef ICMP6_FILTER
338 {
339 struct icmp6_filter filt;
340 if (!(options & O_VERBOSE)) {
341 ICMP6_FILTER_SETBLOCKALL(&filt);
342#if 0
343 if ((options & F_FQDN) || (options & F_FQDNOLD) ||
344 (options & F_NODEADDR) || (options & F_SUPTYPES))
345 ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
346 else
347#endif
348 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
349 } else {
350 ICMP6_FILTER_SETPASSALL(&filt);
351 }
352 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
353 sizeof(filt)) < 0)
354 error_msg_and_die("setsockopt(ICMP6_FILTER)");
355 }
356#endif /*ICMP6_FILTER*/
357
358 /* enable broadcast pings */
359 sockopt = 1;
360 setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
361 sizeof(sockopt));
362
363 /* set recv buf for broadcast pings */
364 sockopt = 48 * 1024;
365 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
366 sizeof(sockopt));
367
368 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
369 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt,
370 sizeof(sockopt));
371
372 sockopt = 1;
373 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *) &sockopt,
374 sizeof(sockopt));
375
376 if (ifname) {
377 if ((pingaddr.sin6_scope_id = if_nametoindex(ifname)) == 0)
378 error_msg_and_die("%s: invalid interface name", ifname);
379 }
380
381 printf("PING %s (%s): %d data bytes\n",
382 hostent->h_name,
383 inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr,
384 buf, sizeof(buf)),
385 datalen);
386
387 signal(SIGINT, pingstats);
388
389 /* start the ping's going ... */
390 sendping(0);
391
392 /* listen for replies */
393 msg.msg_name=&from;
394 msg.msg_namelen=sizeof(from);
395 msg.msg_iov=&iov;
396 msg.msg_iovlen=1;
397 msg.msg_control=control_buf;
398 iov.iov_base=packet;
399 iov.iov_len=sizeof(packet);
400 while (1) {
401 int c;
402 struct cmsghdr *cmsgptr = NULL;
403 int hoplimit=-1;
404 msg.msg_controllen=sizeof(control_buf);
405
406 if ((c = recvmsg(pingsock, &msg, 0)) < 0) {
407 if (errno == EINTR)
408 continue;
409 perror_msg("recvfrom");
410 continue;
411 }
412 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
413 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
414 if (cmsgptr->cmsg_level == SOL_IPV6 &&
415 cmsgptr->cmsg_type == IPV6_HOPLIMIT ) {
416 hoplimit=*(int*)CMSG_DATA(cmsgptr);
417 }
418 }
419 unpack(packet, c, &from, hoplimit);
420 if (pingcount > 0 && nreceived >= pingcount)
421 break;
422 }
423 pingstats(0);
424}
425
426extern int ping6_main(int argc, char **argv)
427{
428 char *thisarg;
429
430 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
431
432 argc--;
433 argv++;
434 options = 0;
435 /* Parse any options */
436 while (argc >= 1 && **argv == '-') {
437 thisarg = *argv;
438 thisarg++;
439 switch (*thisarg) {
440 case 'v':
441 options &= ~O_QUIET;
442 options |= O_VERBOSE;
443 break;
444 case 'q':
445 options &= ~O_VERBOSE;
446 options |= O_QUIET;
447 break;
448 case 'c':
449 if (--argc <= 0)
450 show_usage();
451 argv++;
452 pingcount = atoi(*argv);
453 break;
454 case 's':
455 if (--argc <= 0)
456 show_usage();
457 argv++;
458 datalen = atoi(*argv);
459 break;
460 case 'I':
461 if (--argc <= 0)
462 show_usage();
463 argv++;
464 ifname = *argv;
465 break;
466 default:
467 show_usage();
468 }
469 argc--;
470 argv++;
471 }
472 if (argc < 1)
473 show_usage();
474
475 myid = getpid() & 0xFFFF;
476 ping(*argv);
477 return EXIT_SUCCESS;
478}
479#endif /* ! CONFIG_FEATURE_FANCY_PING6 */
480
481/*
482 * Copyright (c) 1989 The Regents of the University of California.
483 * All rights reserved.
484 *
485 * This code is derived from software contributed to Berkeley by
486 * Mike Muuss.
487 *
488 * Redistribution and use in source and binary forms, with or without
489 * modification, are permitted provided that the following conditions
490 * are met:
491 * 1. Redistributions of source code must retain the above copyright
492 * notice, this list of conditions and the following disclaimer.
493 * 2. Redistributions in binary form must reproduce the above copyright
494 * notice, this list of conditions and the following disclaimer in the
495 * documentation and/or other materials provided with the distribution.
496 *
497 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
498 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
499 *
500 * 4. Neither the name of the University nor the names of its contributors
501 * may be used to endorse or promote products derived from this software
502 * without specific prior written permission.
503 *
504 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
505 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
506 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
507 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
508 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
509 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
510 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
511 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
512 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
513 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
514 * SUCH DAMAGE.
515 */
diff --git a/networking/route.c b/networking/route.c
index 26162ee87..76e76b4b7 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -1,7 +1,7 @@
1/* route 1/* route
2 * 2 *
3 * Similar to the standard Unix route, but with only the necessary 3 * Similar to the standard Unix route, but with only the necessary
4 * parts for AF_INET 4 * parts for AF_INET and AF_INET6
5 * 5 *
6 * Bjorn Wesen, Axis Communications AB 6 * Bjorn Wesen, Axis Communications AB
7 * 7 *
@@ -15,16 +15,19 @@
15 * Foundation; either version 2 of the License, or (at 15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version. 16 * your option) any later version.
17 * 17 *
18 * $Id: route.c,v 1.16 2002/05/16 19:14:15 sandman Exp $ 18 * $Id: route.c,v 1.17 2002/07/03 11:46:34 andersen Exp $
19 * 19 *
20 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> 20 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
21 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov> 21 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
22 *
23 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
22 */ 24 */
23 25
24#include <sys/types.h> 26#include <sys/types.h>
25#include <sys/ioctl.h> 27#include <sys/ioctl.h>
26#include "inet_common.h" 28#include "inet_common.h"
27#include <net/route.h> 29#include <net/route.h>
30#include <net/if.h>
28#include <linux/param.h> // HZ 31#include <linux/param.h> // HZ
29#include <stdio.h> 32#include <stdio.h>
30#include <errno.h> 33#include <errno.h>
@@ -325,6 +328,139 @@ INET_setroute(int action, int options, char **args)
325 return EXIT_SUCCESS; 328 return EXIT_SUCCESS;
326} 329}
327 330
331#if CONFIG_FEATURE_IPV6
332static int INET6_setroute(int action, int options, char **args)
333{
334 struct in6_rtmsg rt;
335 struct ifreq ifr;
336 struct sockaddr_in6 sa6;
337 char target[128], gateway[128] = "NONE";
338 int metric, prefix_len;
339 char *devname = NULL;
340 char *cp;
341 int skfd;
342
343 if (*args == NULL)
344 show_usage();
345
346 strcpy(target, *args++);
347 if (!strcmp(target, "default")) {
348 prefix_len = 0;
349 memset(&sa6, 0, sizeof(sa6));
350 } else {
351 if ((cp = strchr(target, '/'))) {
352 prefix_len = atol(cp + 1);
353 if ((prefix_len < 0) || (prefix_len > 128))
354 show_usage();
355 *cp = 0;
356 } else {
357 prefix_len = 128;
358 }
359 if (INET6_resolve(target, (struct sockaddr_in6 *)&sa6) < 0) {
360 error_msg(_("can't resolve %s"), target);
361 return EXIT_FAILURE; /* XXX change to E_something */
362 }
363 }
364
365 /* Clean out the RTREQ structure. */
366 memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
367
368 memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
369
370 /* Fill in the other fields. */
371 rt.rtmsg_flags = RTF_UP;
372 if (prefix_len == 128)
373 rt.rtmsg_flags |= RTF_HOST;
374 rt.rtmsg_metric = 1;
375 rt.rtmsg_dst_len = prefix_len;
376
377 while (*args) {
378 if (!strcmp(*args, "metric")) {
379
380 args++;
381 if (!*args || !isdigit(**args))
382 show_usage();
383 metric = atoi(*args);
384 rt.rtmsg_metric = metric;
385 args++;
386 continue;
387 }
388 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
389 args++;
390 if (!*args)
391 show_usage();
392 if (rt.rtmsg_flags & RTF_GATEWAY)
393 show_usage();
394 strcpy(gateway, *args);
395 if (INET6_resolve(gateway, (struct sockaddr_in6 *)&sa6) < 0) {
396 error_msg(_("can't resolve gw %s"), gateway);
397 return (E_LOOKUP);
398 }
399 memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
400 sizeof(struct in6_addr));
401 rt.rtmsg_flags |= RTF_GATEWAY;
402 args++;
403 continue;
404 }
405 if (!strcmp(*args, "mod")) {
406 args++;
407 rt.rtmsg_flags |= RTF_MODIFIED;
408 continue;
409 }
410 if (!strcmp(*args, "dyn")) {
411 args++;
412 rt.rtmsg_flags |= RTF_DYNAMIC;
413 continue;
414 }
415 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
416 args++;
417 if (!*args)
418 show_usage();
419 } else if (args[1])
420 show_usage();
421
422 devname = *args;
423 args++;
424 }
425
426 /* Create a socket to the INET6 kernel. */
427 if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
428 perror("socket");
429 return (E_SOCK);
430 }
431 if (devname) {
432 memset(&ifr, 0, sizeof(ifr));
433 strcpy(ifr.ifr_name, devname);
434
435 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
436 perror("SIOGIFINDEX");
437 return (E_SOCK);
438 }
439 rt.rtmsg_ifindex = ifr.ifr_ifindex;
440 } else
441 rt.rtmsg_ifindex = 0;
442
443 /* Tell the kernel to accept this route. */
444 if (action == RTACTION_DEL) {
445 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
446 perror("SIOCDELRT");
447 close(skfd);
448 return (E_SOCK);
449 }
450 } else {
451 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
452 perror("SIOCADDRT");
453 close(skfd);
454 return (E_SOCK);
455 }
456 }
457
458 /* Close the socket. */
459 (void) close(skfd);
460 return (0);
461}
462#endif
463
328#ifndef RTF_UP 464#ifndef RTF_UP
329/* Keep this in sync with /usr/src/linux/include/linux/route.h */ 465/* Keep this in sync with /usr/src/linux/include/linux/route.h */
330#define RTF_UP 0x0001 /* route usable */ 466#define RTF_UP 0x0001 /* route usable */
@@ -418,17 +554,103 @@ void displayroutes(int noresolve, int netstatfmt)
418 } 554 }
419} 555}
420 556
557#if CONFIG_FEATURE_IPV6
558static void INET6_displayroutes(int noresolve)
559{
560 char buff[256];
561 char iface[16], flags[16];
562 char addr6[128], naddr6[128];
563 struct sockaddr_in6 saddr6, snaddr6;
564 int iflags, metric, refcnt, use, prefix_len, slen;
565 int numeric;
566
567 char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
568
569 FILE *fp = xfopen("/proc/net/ipv6_route", "r");
570 flags[0]='U';
571
572 if(noresolve)
573 noresolve = 0x0fff;
574 numeric = noresolve | 0x8000; /* default instead of * */
575
576 printf("Kernel IPv6 routing table\n"
577 "Destination "
578 "Next Hop "
579 "Flags Metric Ref Use Iface\n");
580
581 while( fgets(buff, sizeof(buff), fp) != NULL ) {
582 int ifl;
583
584 if(sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
585 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
586 "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
587 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
588 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
589 &prefix_len,
590 saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
591 saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
592 &slen,
593 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
594 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
595 &metric, &use, &refcnt, &iflags, iface)!=31) {
596 error_msg_and_die( "Unsuported kernel route format\n");
597 }
598
599 ifl = 1; /* parse flags */
600 if (!(iflags & RTF_UP))
601 continue;
602 if (iflags & RTF_GATEWAY)
603 flags[ifl++]='G';
604 if (iflags & RTF_HOST)
605 flags[ifl++]='H';
606 if (iflags & RTF_DEFAULT)
607 flags[ifl++]='D';
608 if (iflags & RTF_ADDRCONF)
609 flags[ifl++]='A';
610 if (iflags & RTF_CACHE)
611 flags[ifl++]='C';
612 flags[ifl]=0;
613
614 /* Fetch and resolve the target address. */
615 snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
616 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
617 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
618 inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
619 saddr6.sin6_family=AF_INET6;
620
621 INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6, numeric);
622 snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
623
624 /* Fetch and resolve the nexthop address. */
625 snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
626 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
627 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
628 inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
629 snaddr6.sin6_family=AF_INET6;
630
631 INET6_rresolve(naddr6, sizeof(naddr6), (struct sockaddr_in6 *) &snaddr6, numeric);
632
633 /* Print the info. */
634 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
635 addr6, naddr6, flags, metric, refcnt, use, iface);
636 }
637}
638#endif
639
421int route_main(int argc, char **argv) 640int route_main(int argc, char **argv)
422{ 641{
423 int opt; 642 int opt;
424 int what = 0; 643 int what = 0;
644#if CONFIG_FEATURE_IPV6
645 int af=AF_INET;
646#endif
425 647
426 if ( !argv [1] || ( argv [1][0] == '-' )) { 648 if ( !argv [1] || ( argv [1][0] == '-' )) {
427 /* check options */ 649 /* check options */
428 int noresolve = 0; 650 int noresolve = 0;
429 int extended = 0; 651 int extended = 0;
430 652
431 while ((opt = getopt(argc, argv, "ne")) > 0) { 653 while ((opt = getopt(argc, argv, "A:ne")) > 0) {
432 switch (opt) { 654 switch (opt) {
433 case 'n': 655 case 'n':
434 noresolve = 1; 656 noresolve = 1;
@@ -436,11 +658,22 @@ int route_main(int argc, char **argv)
436 case 'e': 658 case 'e':
437 extended = 1; 659 extended = 1;
438 break; 660 break;
661 case 'A':
662#if CONFIG_FEATURE_IPV6
663 if (strcmp(optarg, "inet6")==0)
664 af=AF_INET6;
665 break;
666#endif
439 default: 667 default:
440 show_usage ( ); 668 show_usage ( );
441 } 669 }
442 } 670 }
443 671
672#if CONFIG_FEATURE_IPV6
673 if (af==AF_INET6)
674 INET6_displayroutes(*argv != NULL);
675 else
676#endif
444 displayroutes ( noresolve, extended ); 677 displayroutes ( noresolve, extended );
445 return EXIT_SUCCESS; 678 return EXIT_SUCCESS;
446 } else { 679 } else {
@@ -455,5 +688,9 @@ int route_main(int argc, char **argv)
455 show_usage(); 688 show_usage();
456 } 689 }
457 690
691#if CONFIG_FEATURE_IPV6
692 if (af==AF_INET6)
693 return INET6_setroute(what, 0, argv+2);
694#endif
458 return INET_setroute(what, 0, argv+2 ); 695 return INET_setroute(what, 0, argv+2 );
459} 696}