diff --git a/src/bin/network/Jamfile b/src/bin/network/Jamfile index 05d170aa61..1f2e1d53a7 100644 --- a/src/bin/network/Jamfile +++ b/src/bin/network/Jamfile @@ -15,6 +15,7 @@ SubInclude HAIKU_TOP src bin network netstat ; #SubInclude HAIKU_TOP src bin network pppconfig ; #SubInclude HAIKU_TOP src bin network ppp_up ; 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 setwep ; SubInclude HAIKU_TOP src bin network tcpdump ; diff --git a/src/bin/network/ifconfig/ifconfig.cpp b/src/bin/network/ifconfig/ifconfig.cpp index 6ae74eb30b..80a8c53160 100644 --- a/src/bin/network/ifconfig/ifconfig.cpp +++ b/src/bin/network/ifconfig/ifconfig.cpp @@ -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. * * Authors: * Axel Dörfler, axeld@pinc-software.de * Oliver Tappe, zooey@hirschkaefer.de + * Atis Elsts, the.kfx@gmail.com */ @@ -33,30 +34,82 @@ extern const char* __progname; const char* kProgramName = __progname; +enum preferred_output_format { + PREFER_OUTPUT_MASK, + PREFER_OUTPUT_PREFIX_LENGTH, +}; + + struct address_family { int family; const char* name; const char* identifiers[4]; + preferred_output_format preferred_format; 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); }; + +bool initialize_address_families(); + // AF_INET family 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); +// 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[] = { { AF_INET, "inet", {"AF_INET", "inet", "ipv4", NULL}, + PREFER_OUTPUT_MASK, inet_parse_address, + inet_prefix_length_to_mask, + inet_mask_to_prefix_length, 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 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) return false; - sockaddr_in& address = *(sockaddr_in *)_address; + sockaddr_in& address = *(sockaddr_in*)_address; address.sin_family = AF_INET; - address.sin_len = sizeof(struct sockaddr_in); + address.sin_len = sizeof(sockaddr_in); address.sin_port = 0; address.sin_addr = inetAddress; 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 inet_print_address(sockaddr* _address) { - sockaddr_in& address = *(sockaddr_in *)_address; + sockaddr_in& address = *(sockaddr_in*)_address; if (address.sin_family != AF_INET) 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 - @@ -181,12 +358,13 @@ usage(int status) "auto-config] [