Another patch by Atis Elsts:
* Added ping6 command from FreeBSD. * tcpdump is now built with IPv6 supprt. * added IPv6 support to route, and ifconfig (the family stuff should eventually be factored out). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37600 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -15,6 +15,7 @@ SubInclude HAIKU_TOP src bin network netstat ;
|
|||||||
#SubInclude HAIKU_TOP src bin network pppconfig ;
|
#SubInclude HAIKU_TOP src bin network pppconfig ;
|
||||||
#SubInclude HAIKU_TOP src bin network ppp_up ;
|
#SubInclude HAIKU_TOP src bin network ppp_up ;
|
||||||
SubInclude HAIKU_TOP src bin network ping ;
|
SubInclude HAIKU_TOP src bin network ping ;
|
||||||
|
SubInclude HAIKU_TOP src bin network ping6 ;
|
||||||
SubInclude HAIKU_TOP src bin network route ;
|
SubInclude HAIKU_TOP src bin network route ;
|
||||||
SubInclude HAIKU_TOP src bin network setwep ;
|
SubInclude HAIKU_TOP src bin network setwep ;
|
||||||
SubInclude HAIKU_TOP src bin network tcpdump ;
|
SubInclude HAIKU_TOP src bin network tcpdump ;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Axel Dörfler, [email protected]
|
* Axel Dörfler, [email protected]
|
||||||
* Oliver Tappe, [email protected]
|
* Oliver Tappe, [email protected]
|
||||||
|
* Atis Elsts, [email protected]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -33,30 +34,82 @@ extern const char* __progname;
|
|||||||
const char* kProgramName = __progname;
|
const char* kProgramName = __progname;
|
||||||
|
|
||||||
|
|
||||||
|
enum preferred_output_format {
|
||||||
|
PREFER_OUTPUT_MASK,
|
||||||
|
PREFER_OUTPUT_PREFIX_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct address_family {
|
struct address_family {
|
||||||
int family;
|
int family;
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* identifiers[4];
|
const char* identifiers[4];
|
||||||
|
preferred_output_format preferred_format;
|
||||||
bool (*parse_address)(const char* string, sockaddr* _address);
|
bool (*parse_address)(const char* string, sockaddr* _address);
|
||||||
|
bool (*prefix_length_to_mask)(uint8 prefixLength, sockaddr* mask);
|
||||||
|
uint8 (*mask_to_prefix_length)(sockaddr* mask);
|
||||||
void (*print_address)(sockaddr* address);
|
void (*print_address)(sockaddr* address);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool initialize_address_families();
|
||||||
|
|
||||||
// AF_INET family
|
// AF_INET family
|
||||||
static bool inet_parse_address(const char* string, sockaddr* address);
|
static bool inet_parse_address(const char* string, sockaddr* address);
|
||||||
|
static bool inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask);
|
||||||
|
static uint8 inet_mask_to_prefix_length(sockaddr* mask);
|
||||||
static void inet_print_address(sockaddr* address);
|
static void inet_print_address(sockaddr* address);
|
||||||
|
|
||||||
|
// AF_INET6 family
|
||||||
|
static bool inet6_parse_address(const char* string, sockaddr* address);
|
||||||
|
static bool inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask);
|
||||||
|
static uint8 inet6_mask_to_prefix_length(sockaddr* mask);
|
||||||
|
static void inet6_print_address(sockaddr* address);
|
||||||
|
|
||||||
static const address_family kFamilies[] = {
|
static const address_family kFamilies[] = {
|
||||||
{
|
{
|
||||||
AF_INET,
|
AF_INET,
|
||||||
"inet",
|
"inet",
|
||||||
{"AF_INET", "inet", "ipv4", NULL},
|
{"AF_INET", "inet", "ipv4", NULL},
|
||||||
|
PREFER_OUTPUT_MASK,
|
||||||
inet_parse_address,
|
inet_parse_address,
|
||||||
|
inet_prefix_length_to_mask,
|
||||||
|
inet_mask_to_prefix_length,
|
||||||
inet_print_address
|
inet_print_address
|
||||||
},
|
},
|
||||||
{ -1, NULL, {NULL}, NULL, NULL }
|
{
|
||||||
|
AF_INET6,
|
||||||
|
"inet6",
|
||||||
|
{"AF_INET6", "inet6", "ipv6", NULL},
|
||||||
|
PREFER_OUTPUT_PREFIX_LENGTH,
|
||||||
|
inet6_parse_address,
|
||||||
|
inet6_prefix_length_to_mask,
|
||||||
|
inet6_mask_to_prefix_length,
|
||||||
|
inet6_print_address
|
||||||
|
},
|
||||||
|
{ -1, NULL, {NULL}, PREFER_OUTPUT_MASK, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int sAddressFamilySockets[sizeof(kFamilies) / sizeof(kFamilies[0])];
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
initialize_address_families()
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
||||||
|
int fd = socket(kFamilies[i].family, SOCK_DGRAM, 0);
|
||||||
|
if (fd != -1) {
|
||||||
|
sAddressFamilySockets[i] = fd;
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
inet_parse_address(const char* string, sockaddr* _address)
|
inet_parse_address(const char* string, sockaddr* _address)
|
||||||
{
|
{
|
||||||
@@ -65,9 +118,9 @@ inet_parse_address(const char* string, sockaddr* _address)
|
|||||||
if (inet_aton(string, &inetAddress) != 1)
|
if (inet_aton(string, &inetAddress) != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sockaddr_in& address = *(sockaddr_in *)_address;
|
sockaddr_in& address = *(sockaddr_in*)_address;
|
||||||
address.sin_family = AF_INET;
|
address.sin_family = AF_INET;
|
||||||
address.sin_len = sizeof(struct sockaddr_in);
|
address.sin_len = sizeof(sockaddr_in);
|
||||||
address.sin_port = 0;
|
address.sin_port = 0;
|
||||||
address.sin_addr = inetAddress;
|
address.sin_addr = inetAddress;
|
||||||
memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
|
memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
|
||||||
@@ -76,10 +129,50 @@ inet_parse_address(const char* string, sockaddr* _address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask)
|
||||||
|
{
|
||||||
|
if (prefixLength > 32)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sockaddr_in& mask = *(sockaddr_in*)_mask;
|
||||||
|
mask.sin_family = AF_INET;
|
||||||
|
mask.sin_len = sizeof(sockaddr_in);
|
||||||
|
mask.sin_port = 0;
|
||||||
|
memset(&mask.sin_zero[0], 0, sizeof(mask.sin_zero));
|
||||||
|
|
||||||
|
uint32 hostMask = 0;
|
||||||
|
for (uint8 i = 32; i > 32 - prefixLength; i--)
|
||||||
|
hostMask |= 1 << (i - 1);
|
||||||
|
mask.sin_addr.s_addr = htonl(hostMask);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8
|
||||||
|
inet_mask_to_prefix_length(sockaddr* _mask)
|
||||||
|
{
|
||||||
|
sockaddr_in& mask = *(sockaddr_in*)_mask;
|
||||||
|
if (mask.sin_family != AF_INET)
|
||||||
|
return (uint8)-1;
|
||||||
|
|
||||||
|
uint8 result = 0;
|
||||||
|
uint32 hostMask = ntohl(mask.sin_addr.s_addr);
|
||||||
|
for (uint8 i = 32; i > 0; i--) {
|
||||||
|
if (hostMask & (1 << (i - 1)) == 0)
|
||||||
|
break;
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
inet_print_address(sockaddr* _address)
|
inet_print_address(sockaddr* _address)
|
||||||
{
|
{
|
||||||
sockaddr_in& address = *(sockaddr_in *)_address;
|
sockaddr_in& address = *(sockaddr_in*)_address;
|
||||||
|
|
||||||
if (address.sin_family != AF_INET)
|
if (address.sin_family != AF_INET)
|
||||||
return;
|
return;
|
||||||
@@ -88,6 +181,90 @@ inet_print_address(sockaddr* _address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
inet6_parse_address(const char* string, sockaddr* _address)
|
||||||
|
{
|
||||||
|
sockaddr_in6& address = *(sockaddr_in6*)_address;
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
address.sin6_len = sizeof(sockaddr_in6);
|
||||||
|
address.sin6_port = 0;
|
||||||
|
address.sin6_flowinfo = 0;
|
||||||
|
address.sin6_scope_id = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask)
|
||||||
|
{
|
||||||
|
if (prefixLength > 128)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sockaddr_in6& mask = *(sockaddr_in6*)_mask;
|
||||||
|
mask.sin6_family = AF_INET6;
|
||||||
|
mask.sin6_len = sizeof(sockaddr_in6);
|
||||||
|
mask.sin6_port = 0;
|
||||||
|
mask.sin6_flowinfo = 0;
|
||||||
|
mask.sin6_scope_id = 0;
|
||||||
|
memset(mask.sin6_addr.s6_addr, 0, sizeof(in6_addr));
|
||||||
|
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) {
|
||||||
|
if (prefixLength < 8) {
|
||||||
|
const uint8 masks[] = {
|
||||||
|
0x00, 0x80, 0xc0, 0xe0,
|
||||||
|
0xf0, 0xf8, 0xfc, 0xfe
|
||||||
|
};
|
||||||
|
mask.sin6_addr.s6_addr[i] = masks[prefixLength];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask.sin6_addr.s6_addr[i] = 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8
|
||||||
|
inet6_mask_to_prefix_length(sockaddr* _mask)
|
||||||
|
{
|
||||||
|
sockaddr_in6& mask = *(sockaddr_in6*)_mask;
|
||||||
|
if (mask.sin6_family != AF_INET6)
|
||||||
|
return (uint8)~0;
|
||||||
|
|
||||||
|
uint8 result = 0;
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); i++) {
|
||||||
|
for (uint8 j = 0; j < 8; j++) {
|
||||||
|
if (!(mask.sin6_addr.s6_addr[i] & (1 << j)))
|
||||||
|
return result;
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
inet6_print_address(sockaddr* _address)
|
||||||
|
{
|
||||||
|
sockaddr_in6& address = *(sockaddr_in6*)_address;
|
||||||
|
|
||||||
|
if (address.sin6_family != AF_INET6)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char buffer[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
printf("%s",
|
||||||
|
inet_ntop(AF_INET6, &address.sin6_addr, buffer, sizeof(buffer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -181,12 +358,13 @@ usage(int status)
|
|||||||
"auto-config] [<option/flags>...]]\n"
|
"auto-config] [<option/flags>...]]\n"
|
||||||
"\t%s --delete interface [...]\n\n"
|
"\t%s --delete interface [...]\n\n"
|
||||||
"Where <option> can be the following:\n"
|
"Where <option> can be the following:\n"
|
||||||
" netmask <addr> - networking subnet mask\n"
|
" netmask <addr> - networking subnet mask\n"
|
||||||
" broadcast <addr> - set broadcast address\n"
|
" prefixlen <number> - subnet mask length in bits\n"
|
||||||
" peer <addr> - ppp-peer address\n"
|
" broadcast <addr> - set broadcast address\n"
|
||||||
" mtu <bytes> - maximal transfer unit\n"
|
" peer <addr> - ppp-peer address\n"
|
||||||
" metric <number> - metric number to use (defaults to 0)\n"
|
" mtu <bytes> - maximal transfer unit\n"
|
||||||
" media <media> - media type to use (defaults to auto)\n",
|
" metric <number> - metric number to use (defaults to 0)\n"
|
||||||
|
" media <media> - media type to use (defaults to auto)\n",
|
||||||
kProgramName, kProgramName);
|
kProgramName, kProgramName);
|
||||||
for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
|
for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
|
||||||
printf("For %s <media> can be one of: ", kMediaTypes[i].pretty);
|
printf("For %s <media> can be one of: ", kMediaTypes[i].pretty);
|
||||||
@@ -210,8 +388,8 @@ bool
|
|||||||
prepare_request(struct ifreq& request, const char* name)
|
prepare_request(struct ifreq& request, const char* name)
|
||||||
{
|
{
|
||||||
if (strlen(name) > IF_NAMESIZE) {
|
if (strlen(name) > IF_NAMESIZE) {
|
||||||
fprintf(stderr, "%s: interface name \"%s\" is too long.\n", kProgramName,
|
fprintf(stderr, "%s: interface name \"%s\" is too long.\n",
|
||||||
name);
|
kProgramName, name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,21 +427,102 @@ parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
prefix_length_to_mask(int32 familyIndex, const char* argument,
|
||||||
|
struct sockaddr& mask)
|
||||||
|
{
|
||||||
|
if (argument == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
uint32 prefixLength = strtoul(argument, &end, 10);
|
||||||
|
if (end == argument)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return kFamilies[familyIndex].prefix_length_to_mask(
|
||||||
|
(uint8)prefixLength, &mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
find_socket(struct ifreq& request, int addressFamily)
|
||||||
|
{
|
||||||
|
int socket = -1;
|
||||||
|
bool socketExists = false;
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
||||||
|
if (addressFamily != -1 && addressFamily != kFamilies[i].family)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
socket = sAddressFamilySockets[i];
|
||||||
|
if (socket == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
socketExists = true;
|
||||||
|
|
||||||
|
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) {
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketExists && !ok) {
|
||||||
|
fprintf(stderr, "%s: Interface \"%s\" does not exist.\n",
|
||||||
|
kProgramName, request.ifr_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
list_interface(int socket, const char* name)
|
list_interface_address(int socket, const address_family* family,
|
||||||
|
uint32 flags, ifreq* request)
|
||||||
|
{
|
||||||
|
if (ioctl(socket, SIOCGIFADDR, request, sizeof(struct ifreq)) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("\t%s addr: ", family->name);
|
||||||
|
family->print_address(&request->ifr_addr);
|
||||||
|
|
||||||
|
if ((flags & IFF_BROADCAST) != 0
|
||||||
|
&& ioctl(socket, SIOCGIFBRDADDR, request, sizeof(struct ifreq)) == 0
|
||||||
|
&& request->ifr_broadaddr.sa_family == family->family) {
|
||||||
|
printf(", Bcast: ");
|
||||||
|
family->print_address(&request->ifr_broadaddr);
|
||||||
|
}
|
||||||
|
if (ioctl(socket, SIOCGIFNETMASK, request, sizeof(struct ifreq)) == 0
|
||||||
|
&& request->ifr_mask.sa_family == family->family) {
|
||||||
|
switch (family->preferred_format) {
|
||||||
|
case PREFER_OUTPUT_MASK:
|
||||||
|
printf(", Mask: ");
|
||||||
|
family->print_address(&request->ifr_mask);
|
||||||
|
break;
|
||||||
|
case PREFER_OUTPUT_PREFIX_LENGTH:
|
||||||
|
printf(", Prefix Length: %u",
|
||||||
|
family->mask_to_prefix_length(&request->ifr_mask));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
list_interface(const char* name, int addressFamily)
|
||||||
{
|
{
|
||||||
ifreq request;
|
ifreq request;
|
||||||
if (!prepare_request(request, name))
|
if (!prepare_request(request, name))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
|
int socket = find_socket(request, addressFamily);
|
||||||
fprintf(stderr, "%s: Interface \"%s\" does not exist.\n", kProgramName,
|
if (socket == -1)
|
||||||
name);
|
return false;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s", name);
|
printf("%s", name);
|
||||||
size_t length = strlen(name);
|
size_t length = strlen(name);
|
||||||
@@ -286,7 +545,7 @@ list_interface(int socket, const char* name)
|
|||||||
prepare_request(request, request.ifr_parameter.device);
|
prepare_request(request, request.ifr_parameter.device);
|
||||||
if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq))
|
if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq))
|
||||||
== 0) {
|
== 0) {
|
||||||
sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr;
|
sockaddr_dl &link = *(sockaddr_dl*)&request.ifr_addr;
|
||||||
|
|
||||||
switch (link.sdl_type) {
|
switch (link.sdl_type) {
|
||||||
case IFT_ETHER:
|
case IFT_ETHER:
|
||||||
@@ -294,7 +553,7 @@ list_interface(int socket, const char* name)
|
|||||||
type = "Ethernet";
|
type = "Ethernet";
|
||||||
|
|
||||||
if (link.sdl_alen > 0) {
|
if (link.sdl_alen > 0) {
|
||||||
uint8 *mac = (uint8 *)LLADDR(&link);
|
uint8 *mac = (uint8*)LLADDR(&link);
|
||||||
sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x",
|
sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
} else
|
} else
|
||||||
@@ -348,29 +607,11 @@ list_interface(int socket, const char* name)
|
|||||||
flags = request.ifr_flags;
|
flags = request.ifr_flags;
|
||||||
|
|
||||||
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
||||||
int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0);
|
int familySocket = sAddressFamilySockets[i];
|
||||||
if (familySocket < 0)
|
if (familySocket != -1) {
|
||||||
continue;
|
list_interface_address(familySocket, &kFamilies[i],
|
||||||
|
flags, &request);
|
||||||
if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) {
|
|
||||||
printf("\t%s addr: ", kFamilies[i].name);
|
|
||||||
kFamilies[i].print_address(&request.ifr_addr);
|
|
||||||
|
|
||||||
if ((flags & IFF_BROADCAST) != 0
|
|
||||||
&& ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
|
|
||||||
&& request.ifr_broadaddr.sa_family == kFamilies[i].family) {
|
|
||||||
printf(", Bcast: ");
|
|
||||||
kFamilies[i].print_address(&request.ifr_broadaddr);
|
|
||||||
}
|
|
||||||
if (ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
|
|
||||||
&& request.ifr_mask.sa_family == kFamilies[i].family) {
|
|
||||||
printf(", Mask: ");
|
|
||||||
kFamilies[i].print_address(&request.ifr_mask);
|
|
||||||
}
|
|
||||||
putchar('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(familySocket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print MTU, metric, flags
|
// Print MTU, metric, flags
|
||||||
@@ -434,19 +675,22 @@ list_interface(int socket, const char* name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
list_interfaces(int socket, const char* name)
|
list_interfaces(const char* name)
|
||||||
{
|
{
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
list_interface(socket, name);
|
list_interface(name, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a list of all interfaces
|
// get a list of all interfaces
|
||||||
|
|
||||||
|
int socket = sAddressFamilySockets[0];
|
||||||
|
|
||||||
ifconf config;
|
ifconf config;
|
||||||
config.ifc_len = sizeof(config.ifc_value);
|
config.ifc_len = sizeof(config.ifc_value);
|
||||||
if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
|
if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
|
||||||
@@ -469,12 +713,13 @@ list_interfaces(int socket, const char* name)
|
|||||||
if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
|
if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ifreq *interface = (ifreq *)buffer;
|
ifreq* interface = (ifreq*)buffer;
|
||||||
|
|
||||||
for (uint32 i = 0; i < count; i++) {
|
for (uint32 i = 0; i < count; i++) {
|
||||||
list_interface(socket, interface->ifr_name);
|
list_interface(interface->ifr_name, interface->ifr_addr.sa_family);
|
||||||
|
|
||||||
interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len);
|
interface = (ifreq*)((addr_t)interface + IF_NAMESIZE
|
||||||
|
+ interface->ifr_addr.sa_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@@ -482,12 +727,16 @@ list_interfaces(int socket, const char* name)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_interface(int socket, const char* name)
|
delete_interface(const char* name)
|
||||||
{
|
{
|
||||||
ifreq request;
|
ifreq request;
|
||||||
if (!prepare_request(request, name))
|
if (!prepare_request(request, name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
int socket = find_socket(request, -1);
|
||||||
|
if (socket == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
|
if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
|
||||||
fprintf(stderr, "%s: Could not delete interface %s: %s\n",
|
fprintf(stderr, "%s: Could not delete interface %s: %s\n",
|
||||||
kProgramName, name, strerror(errno));
|
kProgramName, name, strerror(errno));
|
||||||
@@ -496,13 +745,27 @@ delete_interface(int socket, const char* name)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
configure_interface(int socket, const char* name, char* const* args,
|
configure_interface(const char* name, char* const* args,
|
||||||
int32 argCount)
|
int32 argCount)
|
||||||
{
|
{
|
||||||
ifreq request;
|
ifreq request;
|
||||||
if (!prepare_request(request, name))
|
if (!prepare_request(request, name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// try to parse address family
|
||||||
|
|
||||||
|
int32 familyIndex;
|
||||||
|
int32 i = 0;
|
||||||
|
if (get_address_family(args[i], familyIndex))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
int socket = sAddressFamilySockets[familyIndex];
|
||||||
|
if (socket < 0) {
|
||||||
|
fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
|
||||||
|
kProgramName, kFamilies[familyIndex].name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
uint32 index = 0;
|
uint32 index = 0;
|
||||||
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
|
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
|
||||||
index = request.ifr_index;
|
index = request.ifr_index;
|
||||||
@@ -513,25 +776,6 @@ configure_interface(int socket, const char* name, char* const* args,
|
|||||||
int mtu = -1, metric = -1, media = -1;
|
int mtu = -1, metric = -1, media = -1;
|
||||||
int addFlags = 0, currentFlags = 0, removeFlags = 0;
|
int addFlags = 0, currentFlags = 0, removeFlags = 0;
|
||||||
|
|
||||||
// try to parse address family
|
|
||||||
|
|
||||||
int32 familyIndex;
|
|
||||||
int32 i = 0;
|
|
||||||
if (get_address_family(args[i], familyIndex))
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (kFamilies[familyIndex].family != AF_INET) {
|
|
||||||
close(socket);
|
|
||||||
|
|
||||||
// replace socket with one of the correct address family
|
|
||||||
socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
|
|
||||||
if (socket < 0) {
|
|
||||||
fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
|
|
||||||
kProgramName, kFamilies[familyIndex].name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
// the interface does not exist yet, we have to add it first
|
// the interface does not exist yet, we have to add it first
|
||||||
request.ifr_parameter.base_name[0] = '\0';
|
request.ifr_parameter.base_name[0] = '\0';
|
||||||
@@ -571,8 +815,8 @@ configure_interface(int socket, const char* name, char* const* args,
|
|||||||
i++;
|
i++;
|
||||||
} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
|
} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
|
||||||
if (hasMask) {
|
if (hasMask) {
|
||||||
fprintf(stderr, "%s: Netmask is specified twice\n",
|
fprintf(stderr, "%s: Netmask or prefix length is specified "
|
||||||
kProgramName);
|
"twice\n", kProgramName);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (!parse_address(familyIndex, args[i + 1], mask)) {
|
if (!parse_address(familyIndex, args[i + 1], mask)) {
|
||||||
@@ -582,6 +826,20 @@ configure_interface(int socket, const char* name, char* const* args,
|
|||||||
}
|
}
|
||||||
hasMask = true;
|
hasMask = true;
|
||||||
i++;
|
i++;
|
||||||
|
} else if (!strcmp(args[i], "prefixlen")
|
||||||
|
|| !strcmp(args[i], "plen")) {
|
||||||
|
if (hasMask) {
|
||||||
|
fprintf(stderr, "%s: Netmask or prefix length is specified "
|
||||||
|
"twice\n", kProgramName);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!prefix_length_to_mask(familyIndex, args[i + 1], mask)) {
|
||||||
|
fprintf(stderr, "%s: Option 'prefixlen' is invalid for this "
|
||||||
|
"address family\n", kProgramName);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
hasMask = true;
|
||||||
|
i++;
|
||||||
} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
|
} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
|
||||||
if (hasBroadcast) {
|
if (hasBroadcast) {
|
||||||
fprintf(stderr, "%s: broadcast address is specified twice\n",
|
fprintf(stderr, "%s: broadcast address is specified twice\n",
|
||||||
@@ -761,6 +1019,7 @@ configure_interface(int socket, const char* name, char* const* args,
|
|||||||
BMessage message(kMsgConfigureInterface);
|
BMessage message(kMsgConfigureInterface);
|
||||||
message.AddString("device", name);
|
message.AddString("device", name);
|
||||||
BMessage address;
|
BMessage address;
|
||||||
|
// TODO: this is not working for ipv6 yet
|
||||||
address.AddString("family", "inet");
|
address.AddString("family", "inet");
|
||||||
address.AddBool("auto_config", true);
|
address.AddBool("auto_config", true);
|
||||||
message.AddMessage("address", &address);
|
message.AddMessage("address", &address);
|
||||||
@@ -807,9 +1066,7 @@ main(int argc, char** argv)
|
|||||||
deleteInterfaces = true;
|
deleteInterfaces = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need a socket to talk to the networking stack
|
if (initialize_address_families() == false) {
|
||||||
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (socket < 0) {
|
|
||||||
fprintf(stderr, "%s: The networking stack doesn't seem to be "
|
fprintf(stderr, "%s: The networking stack doesn't seem to be "
|
||||||
"available.\n", kProgramName);
|
"available.\n", kProgramName);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -817,7 +1074,7 @@ main(int argc, char** argv)
|
|||||||
|
|
||||||
if (deleteInterfaces) {
|
if (deleteInterfaces) {
|
||||||
for (int i = 2; i < argc; i++) {
|
for (int i = 2; i < argc; i++) {
|
||||||
delete_interface(socket, argv[i]);
|
delete_interface(argv[i]);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argc > 1 && !strcmp(argv[1], "-a")) {
|
} else if (argc > 1 && !strcmp(argv[1], "-a")) {
|
||||||
@@ -825,7 +1082,7 @@ main(int argc, char** argv)
|
|||||||
if (argc > 2)
|
if (argc > 2)
|
||||||
usage(1);
|
usage(1);
|
||||||
|
|
||||||
list_interfaces(socket, NULL);
|
list_interfaces(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -833,13 +1090,13 @@ main(int argc, char** argv)
|
|||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
// add or configure an interface
|
// add or configure an interface
|
||||||
|
|
||||||
configure_interface(socket, name, argv + 2, argc - 2);
|
configure_interface(name, argv + 2, argc - 2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// list interfaces
|
// list interfaces
|
||||||
|
|
||||||
list_interfaces(socket, name);
|
list_interfaces(name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
SubDir HAIKU_TOP src bin network ping6 ;
|
||||||
|
|
||||||
|
SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ;
|
||||||
|
|
||||||
|
if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
|
||||||
|
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
|
||||||
|
# We need the public network headers also when not compiling for Haiku.
|
||||||
|
# Unfortunately we get more than we want, namely all POSIX headers.
|
||||||
|
}
|
||||||
|
|
||||||
|
BinCommand ping6 :
|
||||||
|
ping6.c
|
||||||
|
: $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) ;
|
||||||
|
|
||||||
|
# Installation -- in the test directory for the time being
|
||||||
|
HaikuInstall install-networking
|
||||||
|
: [ FDirName $(HAIKU_TEST_DIR) kits net ]
|
||||||
|
: ping6 ;
|
||||||
|
|
||||||
|
HaikuInstall install-userland-networking
|
||||||
|
: [ FDirName $(HAIKU_TEST_DIR) kits net userland ]
|
||||||
|
: ping6
|
||||||
|
: installed-userland-networking
|
||||||
|
;
|
||||||
|
|
||||||
|
Package haiku-networkingkit-cvs :
|
||||||
|
ping6 :
|
||||||
|
boot home Desktop haiku-networkingkit ;
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
+248
-35
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -39,27 +39,56 @@ enum modes {
|
|||||||
RTM_FLUSH,
|
RTM_FLUSH,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum preferred_output_format {
|
||||||
|
PREFER_OUTPUT_MASK,
|
||||||
|
PREFER_OUTPUT_PREFIX_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
struct address_family {
|
struct address_family {
|
||||||
int family;
|
int family;
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* identifiers[4];
|
const char* identifiers[4];
|
||||||
|
preferred_output_format preferred_format;
|
||||||
bool (*parse_address)(const char* string, sockaddr* _address);
|
bool (*parse_address)(const char* string, sockaddr* _address);
|
||||||
|
bool (*prefix_length_to_mask)(uint8 prefixLength, sockaddr* mask);
|
||||||
|
uint8 (*mask_to_prefix_length)(sockaddr* mask);
|
||||||
const char* (*address_to_string)(sockaddr* address);
|
const char* (*address_to_string)(sockaddr* address);
|
||||||
};
|
};
|
||||||
|
|
||||||
// AF_INET family
|
// AF_INET family
|
||||||
static bool inet_parse_address(const char* string, sockaddr* address);
|
static bool inet_parse_address(const char* string, sockaddr* address);
|
||||||
|
static bool inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask);
|
||||||
|
static uint8 inet_mask_to_prefix_length(sockaddr* mask);
|
||||||
static const char* inet_address_to_string(sockaddr* address);
|
static const char* inet_address_to_string(sockaddr* address);
|
||||||
|
|
||||||
|
// AF_INET6 family
|
||||||
|
static bool inet6_parse_address(const char* string, sockaddr* address);
|
||||||
|
static bool inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask);
|
||||||
|
static uint8 inet6_mask_to_prefix_length(sockaddr* mask);
|
||||||
|
static const char* inet6_address_to_string(sockaddr* address);
|
||||||
|
|
||||||
static const address_family kFamilies[] = {
|
static const address_family kFamilies[] = {
|
||||||
{
|
{
|
||||||
AF_INET,
|
AF_INET,
|
||||||
"inet",
|
"inet",
|
||||||
{"AF_INET", "inet", "ipv4", NULL},
|
{"AF_INET", "inet", "ipv4", NULL},
|
||||||
|
PREFER_OUTPUT_MASK,
|
||||||
inet_parse_address,
|
inet_parse_address,
|
||||||
|
inet_prefix_length_to_mask,
|
||||||
|
inet_mask_to_prefix_length,
|
||||||
inet_address_to_string,
|
inet_address_to_string,
|
||||||
},
|
},
|
||||||
{ -1, NULL, {NULL}, NULL, NULL }
|
{
|
||||||
|
AF_INET6,
|
||||||
|
"inet6",
|
||||||
|
{"AF_INET6", "inet6", "ipv6", NULL},
|
||||||
|
PREFER_OUTPUT_PREFIX_LENGTH,
|
||||||
|
inet6_parse_address,
|
||||||
|
inet6_prefix_length_to_mask,
|
||||||
|
inet6_mask_to_prefix_length,
|
||||||
|
inet6_address_to_string,
|
||||||
|
},
|
||||||
|
{ -1, NULL, {NULL}, PREFER_OUTPUT_MASK, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -71,7 +100,7 @@ inet_parse_address(const char* string, sockaddr* _address)
|
|||||||
if (inet_aton(string, &inetAddress) != 1)
|
if (inet_aton(string, &inetAddress) != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sockaddr_in& address = *(sockaddr_in *)_address;
|
sockaddr_in& address = *(sockaddr_in*)_address;
|
||||||
address.sin_family = AF_INET;
|
address.sin_family = AF_INET;
|
||||||
address.sin_len = sizeof(struct sockaddr_in);
|
address.sin_len = sizeof(struct sockaddr_in);
|
||||||
address.sin_port = 0;
|
address.sin_port = 0;
|
||||||
@@ -82,13 +111,143 @@ inet_parse_address(const char* string, sockaddr* _address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *
|
static bool
|
||||||
|
inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask)
|
||||||
|
{
|
||||||
|
if (prefixLength > 32)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sockaddr_in& mask = *(sockaddr_in*)_mask;
|
||||||
|
mask.sin_family = AF_INET;
|
||||||
|
mask.sin_len = sizeof(sockaddr_in);
|
||||||
|
mask.sin_port = 0;
|
||||||
|
memset(&mask.sin_zero[0], 0, sizeof(mask.sin_zero));
|
||||||
|
|
||||||
|
uint32 hostMask = 0;
|
||||||
|
for (uint8 i = 32; i > 32 - prefixLength; i--)
|
||||||
|
hostMask |= 1 << (i - 1);
|
||||||
|
mask.sin_addr.s_addr = htonl(hostMask);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8
|
||||||
|
inet_mask_to_prefix_length(sockaddr* _mask)
|
||||||
|
{
|
||||||
|
if (_mask == NULL)
|
||||||
|
return 32;
|
||||||
|
|
||||||
|
sockaddr_in& mask = *(sockaddr_in*)_mask;
|
||||||
|
if (mask.sin_family != AF_INET)
|
||||||
|
return (uint8)-1;
|
||||||
|
|
||||||
|
uint8 result = 0;
|
||||||
|
uint32 hostMask = ntohl(mask.sin_addr.s_addr);
|
||||||
|
for (uint8 i = 32; i > 0; i--) {
|
||||||
|
if (hostMask & (1 << (i - 1)) == 0)
|
||||||
|
break;
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char*
|
||||||
inet_address_to_string(sockaddr* address)
|
inet_address_to_string(sockaddr* address)
|
||||||
{
|
{
|
||||||
if (address == NULL || address->sa_family != AF_INET)
|
if (address == NULL || address->sa_family != AF_INET)
|
||||||
return "-";
|
return "-";
|
||||||
|
|
||||||
return inet_ntoa(((sockaddr_in *)address)->sin_addr);
|
return inet_ntoa(((sockaddr_in*)address)->sin_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
inet6_parse_address(const char* string, sockaddr* _address)
|
||||||
|
{
|
||||||
|
sockaddr_in6& address = *(sockaddr_in6*)_address;
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
address.sin6_len = sizeof(sockaddr_in6);
|
||||||
|
address.sin6_port = 0;
|
||||||
|
address.sin6_flowinfo = 0;
|
||||||
|
address.sin6_scope_id = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask)
|
||||||
|
{
|
||||||
|
if (prefixLength > 128)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sockaddr_in6& mask = *(sockaddr_in6*)_mask;
|
||||||
|
mask.sin6_family = AF_INET6;
|
||||||
|
mask.sin6_len = sizeof(sockaddr_in6);
|
||||||
|
mask.sin6_port = 0;
|
||||||
|
mask.sin6_flowinfo = 0;
|
||||||
|
mask.sin6_scope_id = 0;
|
||||||
|
memset(mask.sin6_addr.s6_addr, 0, sizeof(in6_addr));
|
||||||
|
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) {
|
||||||
|
if (prefixLength < 8) {
|
||||||
|
const uint8 masks[] = {
|
||||||
|
0x00, 0x80, 0xc0, 0xe0,
|
||||||
|
0xf0, 0xf8, 0xfc, 0xfe
|
||||||
|
};
|
||||||
|
mask.sin6_addr.s6_addr[i] = masks[prefixLength];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask.sin6_addr.s6_addr[i] = 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8
|
||||||
|
inet6_mask_to_prefix_length(sockaddr* _mask)
|
||||||
|
{
|
||||||
|
if (_mask == NULL)
|
||||||
|
return 128;
|
||||||
|
|
||||||
|
sockaddr_in6& mask = *(sockaddr_in6*)_mask;
|
||||||
|
if (mask.sin6_family != AF_INET6)
|
||||||
|
return (uint8)-1;
|
||||||
|
|
||||||
|
uint8 result = 0;
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); i++) {
|
||||||
|
for (uint8 j = 0; j < 8; j++) {
|
||||||
|
if (!(mask.sin6_addr.s6_addr[i] & (1 << j)))
|
||||||
|
return result;
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
inet6_address_to_string(sockaddr* address)
|
||||||
|
{
|
||||||
|
if (address == NULL || address->sa_family != AF_INET6)
|
||||||
|
return "-";
|
||||||
|
|
||||||
|
static char buffer[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
inet_ntop(AF_INET6, &((sockaddr_in6*)address)->sin6_addr,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -98,15 +257,17 @@ inet_address_to_string(sockaddr* address)
|
|||||||
void
|
void
|
||||||
usage(int status)
|
usage(int status)
|
||||||
{
|
{
|
||||||
printf("usage: %s [command] [<interface>] [<address family>] <address|default> [<option/flags>...]\n"
|
printf("usage: %s [command] [<interface>] [<address family>] "
|
||||||
|
"<address|default> [<option/flags>...]\n"
|
||||||
"Where <command> can be the one of:\n"
|
"Where <command> can be the one of:\n"
|
||||||
" add - add a route for the specified interface\n"
|
" add - add a route for the specified interface\n"
|
||||||
" delete - deletes the specified route\n"
|
" delete - deletes the specified route\n"
|
||||||
" list - list with filters [default]\n"
|
" list - list with filters [default]\n"
|
||||||
"<option> can be the following:\n"
|
"<option> can be the following:\n"
|
||||||
" netmask <addr> - networking subnet mask\n"
|
" netmask <addr> - networking subnet mask\n"
|
||||||
" gw <addr> - gateway address\n"
|
" prefixlen <number> - subnet mask length in bits\n"
|
||||||
" mtu <bytes> - maximal transfer unit\n"
|
" gw <addr> - gateway address\n"
|
||||||
|
" mtu <bytes> - maximal transfer unit\n"
|
||||||
"And <flags> can be: reject, local, host\n\n"
|
"And <flags> can be: reject, local, host\n\n"
|
||||||
"Example:\n"
|
"Example:\n"
|
||||||
"\t%s add /dev/net/ipro1000/0 default gw 192.168.0.254\n",
|
"\t%s add /dev/net/ipro1000/0 default gw 192.168.0.254\n",
|
||||||
@@ -120,7 +281,8 @@ bool
|
|||||||
prepare_request(struct ifreq& request, const char* name)
|
prepare_request(struct ifreq& request, const char* name)
|
||||||
{
|
{
|
||||||
if (strlen(name) > IF_NAMESIZE) {
|
if (strlen(name) > IF_NAMESIZE) {
|
||||||
fprintf(stderr, "%s: interface name \"%s\" is too long.\n", kProgramName, name);
|
fprintf(stderr, "%s: interface name \"%s\" is too long.\n",
|
||||||
|
kProgramName, name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,12 +311,30 @@ get_address_family(const char* argument, int32& familyIndex)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
parse_address(int32 familyIndex, const char* argument, struct sockaddr_storage& address)
|
parse_address(int32 familyIndex, const char* argument,
|
||||||
|
struct sockaddr_storage& address)
|
||||||
{
|
{
|
||||||
if (argument == NULL)
|
if (argument == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return kFamilies[familyIndex].parse_address(argument, (sockaddr *)&address);
|
return kFamilies[familyIndex].parse_address(argument, (sockaddr*)&address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
prefix_length_to_mask(int32 familyIndex, const char* argument,
|
||||||
|
struct sockaddr_storage& mask)
|
||||||
|
{
|
||||||
|
if (argument == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
uint32 prefixLength = strtoul(argument, &end, 10);
|
||||||
|
if (end == argument)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return kFamilies[familyIndex].prefix_length_to_mask(
|
||||||
|
(uint8)prefixLength, (sockaddr*)&mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -172,10 +352,8 @@ list_routes(int socket, const char *interfaceName, route_entry &route)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 size = (uint32)config.ifc_value;
|
uint32 size = (uint32)config.ifc_value;
|
||||||
if (size == 0) {
|
if (size == 0)
|
||||||
fprintf(stderr, "%s: There are no routes!\n", kProgramName);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
void *buffer = malloc(size);
|
void *buffer = malloc(size);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
@@ -188,14 +366,15 @@ list_routes(int socket, const char *interfaceName, route_entry &route)
|
|||||||
if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
|
if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ifreq *interface = (ifreq *)buffer;
|
ifreq *interface = (ifreq*)buffer;
|
||||||
ifreq *end = (ifreq *)((uint8 *)buffer + size);
|
ifreq *end = (ifreq*)((uint8*)buffer + size);
|
||||||
|
|
||||||
while (interface < end) {
|
while (interface < end) {
|
||||||
route_entry& route = interface->ifr_route;
|
route_entry& route = interface->ifr_route;
|
||||||
|
|
||||||
// apply filters
|
// apply filters
|
||||||
if (interfaceName == NULL || !strcmp(interfaceName, interface->ifr_name)) {
|
if (interfaceName == NULL
|
||||||
|
|| !strcmp(interfaceName, interface->ifr_name)) {
|
||||||
// find family
|
// find family
|
||||||
const address_family *family = NULL;
|
const address_family *family = NULL;
|
||||||
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
||||||
@@ -206,11 +385,22 @@ list_routes(int socket, const char *interfaceName, route_entry &route)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (family != NULL) {
|
if (family != NULL) {
|
||||||
printf("%15s ", family->address_to_string(route.destination));
|
// TODO: is the %15s format OK for IPv6?
|
||||||
printf("mask %-15s ", family->address_to_string(route.mask));
|
printf("%15s", family->address_to_string(route.destination));
|
||||||
|
switch (family->preferred_format) {
|
||||||
if (route.flags & RTF_GATEWAY)
|
case PREFER_OUTPUT_MASK:
|
||||||
printf("gateway %-15s ", family->address_to_string(route.gateway));
|
printf(" mask %-15s ",
|
||||||
|
family->address_to_string(route.mask));
|
||||||
|
break;
|
||||||
|
case PREFER_OUTPUT_PREFIX_LENGTH:
|
||||||
|
printf("/%u ",
|
||||||
|
family->mask_to_prefix_length(route.mask));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((route.flags & RTF_GATEWAY) != 0) {
|
||||||
|
printf("gateway %-15s ",
|
||||||
|
family->address_to_string(route.gateway));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("unknown family ");
|
printf("unknown family ");
|
||||||
}
|
}
|
||||||
@@ -254,7 +444,7 @@ list_routes(int socket, const char *interfaceName, route_entry &route)
|
|||||||
if (route.gateway != NULL)
|
if (route.gateway != NULL)
|
||||||
addressSize += route.gateway->sa_len;
|
addressSize += route.gateway->sa_len;
|
||||||
|
|
||||||
interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + sizeof(route_entry)
|
interface = (ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(route_entry)
|
||||||
+ addressSize);
|
+ addressSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,8 +511,17 @@ get_route(int socket, route_entry &route)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (family != NULL) {
|
if (family != NULL) {
|
||||||
printf("%s ", family->address_to_string(request.destination));
|
printf("%s", family->address_to_string(request.destination));
|
||||||
printf("mask %s ", family->address_to_string(request.mask));
|
switch (family->preferred_format) {
|
||||||
|
case PREFER_OUTPUT_MASK:
|
||||||
|
printf(" mask %s ",
|
||||||
|
family->address_to_string(request.mask));
|
||||||
|
break;
|
||||||
|
case PREFER_OUTPUT_PREFIX_LENGTH:
|
||||||
|
printf("/%u ",
|
||||||
|
family->mask_to_prefix_length(request.mask));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.flags & RTF_GATEWAY)
|
if (request.flags & RTF_GATEWAY)
|
||||||
printf("gateway %s ", family->address_to_string(request.gateway));
|
printf("gateway %s ", family->address_to_string(request.gateway));
|
||||||
@@ -386,7 +585,8 @@ main(int argc, char** argv)
|
|||||||
|
|
||||||
while (i < argc && i < 5) {
|
while (i < argc && i < 5) {
|
||||||
// try to parse address family
|
// try to parse address family
|
||||||
if (i <= 3 && familyIndex == -1 && get_address_family(argv[i], familyIndex)) {
|
if (i <= 3 && familySpecified == false
|
||||||
|
&& get_address_family(argv[i], familyIndex)) {
|
||||||
familySpecified = true;
|
familySpecified = true;
|
||||||
if (i == 2)
|
if (i == 2)
|
||||||
interfaceIndex = -1;
|
interfaceIndex = -1;
|
||||||
@@ -432,7 +632,7 @@ main(int argc, char** argv)
|
|||||||
i++;
|
i++;
|
||||||
} else if (!strcmp(argv[i], "nm") || !strcmp(argv[i], "netmask")) {
|
} else if (!strcmp(argv[i], "nm") || !strcmp(argv[i], "netmask")) {
|
||||||
if (hasMask) {
|
if (hasMask) {
|
||||||
fprintf(stderr, "%s: Netmask is specified twice\n",
|
fprintf(stderr, "%s: Netmask or prefix length is specified twice\n",
|
||||||
kProgramName);
|
kProgramName);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -443,6 +643,19 @@ main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
hasMask = true;
|
hasMask = true;
|
||||||
i++;
|
i++;
|
||||||
|
} else if (!strcmp(argv[i], "plen") || !strcmp(argv[i], "prefixlen")) {
|
||||||
|
if (hasMask) {
|
||||||
|
fprintf(stderr, "%s: Netmask or prefix length is specified twice\n",
|
||||||
|
kProgramName);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!prefix_length_to_mask(familyIndex, argv[i + 1], mask)) {
|
||||||
|
fprintf(stderr, "%s: Option 'prefixlen' is invalid for this "
|
||||||
|
"address family\n", kProgramName);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
hasMask = true;
|
||||||
|
i++;
|
||||||
} else if (!strcmp(argv[i], "mtu")) {
|
} else if (!strcmp(argv[i], "mtu")) {
|
||||||
route.mtu = argv[i + 1] ? strtol(argv[i + 1], NULL, 0) : 0;
|
route.mtu = argv[i + 1] ? strtol(argv[i + 1], NULL, 0) : 0;
|
||||||
if (route.mtu <= 500) {
|
if (route.mtu <= 500) {
|
||||||
@@ -464,11 +677,11 @@ main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasDestination)
|
if (hasDestination)
|
||||||
route.destination = (sockaddr *)&destination;
|
route.destination = (sockaddr*)&destination;
|
||||||
if (hasMask)
|
if (hasMask)
|
||||||
route.mask = (sockaddr *)&mask;
|
route.mask = (sockaddr*)&mask;
|
||||||
if (hasGateway) {
|
if (hasGateway) {
|
||||||
route.gateway = (sockaddr *)&gateway;
|
route.gateway = (sockaddr*)&gateway;
|
||||||
route.flags |= RTF_GATEWAY;
|
route.flags |= RTF_GATEWAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +718,7 @@ main(int argc, char** argv)
|
|||||||
list_routes(socket, interface, route);
|
list_routes(socket, interface, route);
|
||||||
else {
|
else {
|
||||||
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
|
||||||
int socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
|
int socket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0);
|
||||||
if (socket < 0)
|
if (socket < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
|
|||||||
UseHeaders [ FDirName $(SUBDIR) ] : true ;
|
UseHeaders [ FDirName $(SUBDIR) ] : true ;
|
||||||
UseHeaders [ FDirName $(SUBDIR) libpcap ] : true ;
|
UseHeaders [ FDirName $(SUBDIR) libpcap ] : true ;
|
||||||
|
|
||||||
local defines = [ FDefines HAVE_CONFIG_H=1 _U_=\"__attribute__((unused))\" ] ;
|
local defines = [ FDefines HAVE_CONFIG_H=1 _U_=\"__attribute__((unused))\" INET6=1 HAVE_SOCKADDR_STORAGE=1 ] ;
|
||||||
|
|
||||||
SubDirCcFlags $(defines) ;
|
SubDirCcFlags $(defines) ;
|
||||||
SubDirC++Flags $(defines) ;
|
SubDirC++Flags $(defines) ;
|
||||||
@@ -39,7 +39,7 @@ BinCommand tcpdump :
|
|||||||
print-cnfp.c
|
print-cnfp.c
|
||||||
print-dccp.c
|
print-dccp.c
|
||||||
print-decnet.c
|
print-decnet.c
|
||||||
#print-dhcp6.c
|
print-dhcp6.c
|
||||||
print-domain.c
|
print-domain.c
|
||||||
print-dvmrp.c
|
print-dvmrp.c
|
||||||
print-eap.c
|
print-eap.c
|
||||||
@@ -50,16 +50,16 @@ BinCommand tcpdump :
|
|||||||
print-ether.c
|
print-ether.c
|
||||||
print-fddi.c
|
print-fddi.c
|
||||||
print-fr.c
|
print-fr.c
|
||||||
#print-frag6.c
|
print-frag6.c
|
||||||
print-gre.c
|
print-gre.c
|
||||||
print-hsrp.c
|
print-hsrp.c
|
||||||
print-icmp.c
|
print-icmp.c
|
||||||
#print-icmp6.c
|
print-icmp6.c
|
||||||
print-igmp.c
|
print-igmp.c
|
||||||
print-igrp.c
|
print-igrp.c
|
||||||
print-ip.c
|
print-ip.c
|
||||||
#print-ip6.c
|
print-ip6.c
|
||||||
#print-ip6opts.c
|
print-ip6opts.c
|
||||||
print-ipcomp.c
|
print-ipcomp.c
|
||||||
print-ipfc.c
|
print-ipfc.c
|
||||||
print-ipx.c
|
print-ipx.c
|
||||||
@@ -83,7 +83,7 @@ BinCommand tcpdump :
|
|||||||
print-ntp.c
|
print-ntp.c
|
||||||
print-null.c
|
print-null.c
|
||||||
print-ospf.c
|
print-ospf.c
|
||||||
#print-ospf6.c
|
print-ospf6.c
|
||||||
print-pflog.c
|
print-pflog.c
|
||||||
print-pgm.c
|
print-pgm.c
|
||||||
print-pim.c
|
print-pim.c
|
||||||
@@ -95,7 +95,7 @@ BinCommand tcpdump :
|
|||||||
print-rip.c
|
print-rip.c
|
||||||
print-ripng.c
|
print-ripng.c
|
||||||
print-rsvp.c
|
print-rsvp.c
|
||||||
#print-rt6.c
|
print-rt6.c
|
||||||
print-rx.c
|
print-rx.c
|
||||||
print-sctp.c
|
print-sctp.c
|
||||||
print-sip.c
|
print-sip.c
|
||||||
|
|||||||
Reference in New Issue
Block a user