2 * Copyright 2006-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
7 * Alexander von Gluck <kallisti5@unixzen.com>
11 #include <arpa/inet.h>
13 #include <net/if_dl.h>
14 #include <net/if_types.h>
15 #include <netinet/in.h>
16 #include <sys/socket.h>
17 #include <sys/sockio.h>
25 #include <NetworkAddress.h>
28 extern const char* __progname
;
29 const char* kProgramName
= __progname
;
43 enum preferredPrefixFormat
{
44 PREFIX_PREFER_NETMASK
= 0,
48 struct address_family
{
51 const char* identifiers
[4];
53 int preferredPrefixFormat
;
56 static const address_family kFamilies
[] = {
60 {"AF_INET", "inet", "ipv4", NULL
},
62 PREFIX_PREFER_NETMASK
,
67 {"AF_INET6", "inet6", "ipv6", NULL
},
71 { -1, NULL
, {NULL
}, -1, -1 }
78 printf("usage: %s [command] [<interface>] [<address family>] "
79 "<address|default> [<option/flags>...]\n"
80 "Where <command> can be the one of:\n"
81 " add - add a route for the specified interface\n"
82 " delete - deletes the specified route\n"
83 " list - list with filters [default]\n"
84 "<option> can be the following:\n"
85 " netmask <addr> - networking subnet mask\n"
86 " prefixlen <number> - subnet mask length in bits\n"
87 " gw <addr> - gateway address\n"
88 " mtu <bytes> - maximal transfer unit\n"
89 "And <flags> can be: reject, local, host\n\n"
91 "\t%s add /dev/net/ipro1000/0 default gw 192.168.0.254\n",
92 kProgramName
, kProgramName
);
99 prepare_request(struct ifreq
& request
, const char* name
)
101 if (strlen(name
) >= IF_NAMESIZE
) {
102 fprintf(stderr
, "%s: interface name \"%s\" is too long.\n",
107 strcpy(request
.ifr_name
, name
);
113 get_address_family(const char* argument
, int32
& familyIndex
)
115 for (int32 i
= 0; kFamilies
[i
].family
>= 0; i
++) {
116 for (int32 j
= 0; kFamilies
[i
].identifiers
[j
]; j
++) {
117 if (!strcmp(argument
, kFamilies
[i
].identifiers
[j
])) {
125 // defaults to AF_INET
132 parse_address(int32 familyIndex
, const char* argument
, BNetworkAddress
& address
)
134 if (argument
== NULL
)
137 return address
.SetTo(kFamilies
[familyIndex
].family
, argument
,
138 (uint16
)0, B_NO_ADDRESS_RESOLUTION
) == B_OK
;
143 prefix_length_to_mask(int32 familyIndex
, const char* argument
,
144 BNetworkAddress
& mask
)
146 if (argument
== NULL
)
150 uint32 prefixLength
= strtoul(argument
, &end
, 10);
154 return mask
.SetToMask(kFamilies
[familyIndex
].family
, prefixLength
) == B_OK
;
162 list_routes(int socket
, const char *interfaceName
, route_entry
&route
)
164 // get a list of all routes
167 config
.ifc_len
= sizeof(config
.ifc_value
);
168 if (ioctl(socket
, SIOCGRTSIZE
, &config
, sizeof(struct ifconf
)) < 0)
171 uint32 size
= (uint32
)config
.ifc_value
;
175 void *buffer
= malloc(size
);
176 if (buffer
== NULL
) {
177 fprintf(stderr
, "%s: Out of memory.\n", kProgramName
);
181 config
.ifc_len
= size
;
182 config
.ifc_buf
= buffer
;
183 if (ioctl(socket
, SIOCGRTTABLE
, &config
, sizeof(struct ifconf
)) < 0)
186 ifreq
*interface
= (ifreq
*)buffer
;
187 ifreq
*end
= (ifreq
*)((uint8
*)buffer
+ size
);
189 // find family (we use the family of the first address as this is
190 // called on a socket for a single family)
191 const address_family
*family
= NULL
;
192 for (int32 i
= 0; kFamilies
[i
].family
>= 0; i
++) {
193 if (interface
->ifr_route
.destination
->sa_family
194 == kFamilies
[i
].family
) {
195 family
= &kFamilies
[i
];
200 int addressLength
= family
->maxAddressLength
;
202 printf("%s routing table:\n", family
->name
);
204 if (family
->preferredPrefixFormat
== PREFIX_PREFER_NETMASK
) {
205 printf("%*s %*s %*s Flags Interface\n", addressLength
, "Destination",
206 addressLength
, "Netmask", addressLength
, "Gateway");
208 printf("%*s %*s Flags Interface\n", addressLength
, "Destination",
209 addressLength
, "Gateway");
212 while (interface
< end
) {
213 route_entry
& route
= interface
->ifr_route
;
216 if (interfaceName
== NULL
217 || !strcmp(interfaceName
, interface
->ifr_name
)) {
219 if (family
!= NULL
) {
220 BNetworkAddress
destination(*route
.destination
);
221 printf("%*s", addressLength
, destination
.ToString().String());
222 if (route
.mask
!= NULL
) {
223 BNetworkAddress mask
;
224 mask
.SetTo(*route
.mask
);
225 if (family
->preferredPrefixFormat
226 == PREFIX_PREFER_NETMASK
) {
227 printf(" %*s ", addressLength
,
228 mask
.ToString().String());
230 printf("/%-3zd ", mask
.PrefixLength());
233 if (family
->preferredPrefixFormat
234 == PREFIX_PREFER_NETMASK
) {
235 printf(" %*s ", addressLength
, "-");
240 if ((route
.flags
& RTF_GATEWAY
) != 0) {
241 BNetworkAddress gateway
;
242 if (route
.gateway
!= NULL
)
243 gateway
.SetTo(*route
.gateway
);
244 printf("%*s ", addressLength
, gateway
.ToString().String());
246 printf("%*s ", family
->maxAddressLength
, "-");
248 printf("unknown family ");
250 if (route
.flags
!= 0) {
262 for (uint32 i
= 0; i
< sizeof(kFlags
) / sizeof(kFlags
[0]);
264 if ((route
.flags
& kFlags
[i
].value
) != 0) {
265 printf(kFlags
[i
].name
);
273 printf("%s", interface
->ifr_name
);
277 int32 addressSize
= 0;
278 if (route
.destination
!= NULL
)
279 addressSize
+= route
.destination
->sa_len
;
280 if (route
.mask
!= NULL
)
281 addressSize
+= route
.mask
->sa_len
;
282 if (route
.gateway
!= NULL
)
283 addressSize
+= route
.gateway
->sa_len
;
285 interface
= (ifreq
*)((addr_t
)interface
+ IF_NAMESIZE
286 + sizeof(route_entry
) + addressSize
);
295 delete_route(int socket
, const char *interface
, route_entry
&route
)
298 if (!prepare_request(request
, interface
))
301 request
.ifr_route
= route
;
303 if (ioctl(socket
, SIOCDELRT
, &request
, sizeof(request
)) < 0) {
304 fprintf(stderr
, "%s: Could not delete route for %s: %s\n",
305 kProgramName
, interface
, strerror(errno
));
311 add_route(int socket
, const char *interface
, route_entry
&route
)
314 if (!prepare_request(request
, interface
))
317 route
.flags
|= RTF_STATIC
;
318 request
.ifr_route
= route
;
320 if (ioctl(socket
, SIOCADDRT
, &request
, sizeof(request
)) < 0) {
321 fprintf(stderr
, "%s: Could not add route for %s: %s\n",
322 kProgramName
, interface
, strerror(errno
));
328 get_route(int socket
, route_entry
&route
)
337 if (ioctl(socket
, SIOCGETRT
, buffer
, sizeof(buffer
)) < 0) {
338 fprintf(stderr
, "%s: Could not get route: %s\n",
339 kProgramName
, strerror(errno
));
344 const address_family
*family
= NULL
;
345 for (int32 i
= 0; kFamilies
[i
].family
>= 0; i
++) {
346 if (route
.destination
->sa_family
== kFamilies
[i
].family
) {
347 family
= &kFamilies
[i
];
352 if (family
!= NULL
) {
353 BNetworkAddress
destination(*request
.destination
);
354 BNetworkAddress
mask(*request
.mask
);
355 printf("%s", destination
.ToString().String());
356 printf("/%zd ", mask
.PrefixLength());
358 BNetworkAddress
gateway(*request
.gateway
);
359 if (request
.flags
& RTF_GATEWAY
)
360 printf("gateway %s ", gateway
.ToString().String());
362 BNetworkAddress
source(*request
.source
);
363 printf("source %s\n", source
.ToString().String());
365 printf("unknown family ");
374 main(int argc
, char** argv
)
376 if (argc
> 1 && (!strcmp(argv
[1], "--help") || !strcmp(argv
[1], "-h")))
379 int32 mode
= RTM_LIST
;
382 if (!strcmp(argv
[1], "delete")
383 || !strcmp(argv
[1], "del")
384 || !strcmp(argv
[1], "-d")) {
390 } else if (!strcmp(argv
[1], "add")
391 || !strcmp(argv
[1], "-a")) {
397 } else if (!strcmp(argv
[1], "get")) {
398 // get route for destination
407 int32 interfaceIndex
= i
;
408 bool familySpecified
= false;
409 int32 familyIndex
= 0;
410 const char *interface
= NULL
;
411 BNetworkAddress destination
;
412 BNetworkAddress mask
;
413 BNetworkAddress gateway
;
414 bool defaultRoute
= false;
417 memset(&route
, 0, sizeof(route_entry
));
419 while (i
< argc
&& i
< 5) {
420 // try to parse address family
421 if (i
<= 3 && familySpecified
== false
422 && get_address_family(argv
[i
], familyIndex
)) {
423 familySpecified
= true;
428 if (!strcmp(argv
[i
], "default")) {
430 route
.flags
= RTF_DEFAULT
;
433 } else if (parse_address(familyIndex
, argv
[i
], destination
)) {
441 if (!defaultRoute
&& destination
.IsEmpty() && mode
!= RTM_LIST
)
446 if (interfaceIndex
!= -1 && interfaceIndex
< argc
)
447 interface
= argv
[interfaceIndex
];
449 if (i
< argc
&& parse_address(familyIndex
, argv
[i
], mask
))
452 // parse options and flags
455 if (!strcmp(argv
[i
], "gw") || !strcmp(argv
[i
], "gateway")) {
456 if (!parse_address(familyIndex
, argv
[i
+ 1], gateway
)) {
457 fprintf(stderr
, "%s: Option 'gw' needs valid address "
458 "parameter\n", kProgramName
);
462 } else if (!strcmp(argv
[i
], "nm") || !strcmp(argv
[i
], "netmask")) {
463 if (!mask
.IsEmpty()) {
464 fprintf(stderr
, "%s: Netmask or prefix length is specified "
465 "twice\n", kProgramName
);
468 if (!parse_address(familyIndex
, argv
[i
+ 1], mask
)) {
469 fprintf(stderr
, "%s: Option 'netmask' needs valid address "
470 "parameter\n", kProgramName
);
474 } else if (!strcmp(argv
[i
], "plen") || !strcmp(argv
[i
], "prefixlen")
475 || !strcmp(argv
[i
], "prefix-length")) {
476 if (!mask
.IsEmpty()) {
477 fprintf(stderr
, "%s: Netmask or prefix length is specified "
478 "twice\n", kProgramName
);
481 if (!prefix_length_to_mask(familyIndex
, argv
[i
+ 1], mask
)) {
482 fprintf(stderr
, "%s: Option 'prefixlen' is invalid for this "
483 "address family\n", kProgramName
);
487 } else if (!strcmp(argv
[i
], "mtu")) {
488 route
.mtu
= argv
[i
+ 1] ? strtol(argv
[i
+ 1], NULL
, 0) : 0;
489 if (route
.mtu
<= 500) {
490 fprintf(stderr
, "%s: Option 'mtu' exptected valid max transfer "
491 "unit size\n", kProgramName
);
495 } else if (!strcmp(argv
[i
], "host")) {
496 route
.flags
|= RTF_HOST
;
497 } else if (!strcmp(argv
[i
], "local")) {
498 route
.flags
|= RTF_LOCAL
;
499 } else if (!strcmp(argv
[i
], "reject")) {
500 route
.flags
|= RTF_REJECT
;
507 if (!destination
.IsEmpty())
508 route
.destination
= (sockaddr
*)destination
;
510 route
.mask
= (sockaddr
*)mask
;
511 if (!gateway
.IsEmpty()) {
512 route
.gateway
= (sockaddr
*)gateway
;
513 route
.flags
|= RTF_GATEWAY
;
516 // we need a socket to talk to the networking stack
517 int socket
= ::socket(kFamilies
[familyIndex
].family
, SOCK_DGRAM
, 0);
519 fprintf(stderr
, "%s: The requested address family is not available.\n",
526 if (interface
== NULL
) {
527 fprintf(stderr
, "%s: You need to specify an interface when "
528 "adding a route.\n", kProgramName
);
532 add_route(socket
, interface
, route
);
535 if (interface
== NULL
) {
536 fprintf(stderr
, "%s: You need to specify an interface when "
537 "removing a route.\n", kProgramName
);
541 delete_route(socket
, interface
, route
);
546 list_routes(socket
, interface
, route
);
548 for (int32 i
= 0; kFamilies
[i
].family
>= 0; i
++) {
549 int socket
= ::socket(kFamilies
[i
].family
, SOCK_DGRAM
, 0);
553 list_routes(socket
, interface
, route
);
560 get_route(socket
, route
);