* ifconfig is no longer using any ioctl()s, but the new C++ classes only. Seems

to work fine so far.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38061 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-08-12 13:51:34 +00:00
parent 97ef73e074
commit 97dfb56d81
1 changed files with 163 additions and 338 deletions

View File

@ -9,16 +9,9 @@
*/
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <errno.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -41,107 +34,13 @@ enum preferred_output_format {
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 initialize_address_families();
// AF_INET family
static bool inet_parse_address(const char* string, sockaddr* address);
// AF_INET6 family
static bool inet6_parse_address(const char* string, sockaddr* address);
static const address_family kFamilies[] = {
{
AF_INET,
"inet",
{"AF_INET", "inet", "ipv4", NULL},
PREFER_OUTPUT_MASK,
inet_parse_address,
},
{
AF_INET6,
"inet6",
{"AF_INET6", "inet6", "ipv6", NULL},
PREFER_OUTPUT_PREFIX_LENGTH,
inet6_parse_address,
},
{ -1, NULL, {NULL}, PREFER_OUTPUT_MASK, 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;
}
// #pragma mark - IPv4
static bool
inet_parse_address(const char* string, sockaddr* _address)
{
in_addr inetAddress;
if (inet_aton(string, &inetAddress) != 1)
return false;
sockaddr_in& address = *(sockaddr_in*)_address;
address.sin_family = AF_INET;
address.sin_len = sizeof(sockaddr_in);
address.sin_port = 0;
address.sin_addr = inetAddress;
memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
return true;
}
// #pragma mark - IPv6
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;
}
// #pragma mark -
struct media_type {
int type;
const char* name;
@ -160,6 +59,22 @@ struct media_type {
};
static const address_family kFamilies[] = {
{
AF_INET,
"inet",
{"AF_INET", "inet", "ipv4", NULL},
PREFER_OUTPUT_MASK
},
{
AF_INET6,
"inet6",
{"AF_INET6", "inet6", "ipv6", NULL},
PREFER_OUTPUT_PREFIX_LENGTH
},
{ -1, NULL, {NULL}, PREFER_OUTPUT_MASK }
};
static const media_type kMediaTypes[] = {
{
0, // for generic options
@ -199,30 +114,7 @@ static const media_type kMediaTypes[] = {
};
static bool
media_parse_subtype(const char* string, int media, int* type)
{
for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
// only check for generic or correct subtypes
if (kMediaTypes[i].type &&
kMediaTypes[i].type != media)
continue;
for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
if (strcmp(kMediaTypes[i].subtypes[j].name, string) == 0) {
// found a match
*type = kMediaTypes[i].subtypes[j].subtype;
return true;
}
}
}
return false;
}
// #pragma mark -
void
static void
usage(int status)
{
printf("usage: %s [<interface> [<address family>] [<address> [<mask>] | "
@ -255,42 +147,46 @@ usage(int status)
}
bool
prepare_request(struct ifreq& request, const char* name)
static bool
media_parse_subtype(const char* string, int media, int* type)
{
if (strlen(name) >= IF_NAMESIZE) {
fprintf(stderr, "%s: interface name \"%s\" is too long.\n",
kProgramName, name);
return false;
for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
// only check for generic or correct subtypes
if (kMediaTypes[i].type &&
kMediaTypes[i].type != media)
continue;
for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
if (strcmp(kMediaTypes[i].subtypes[j].name, string) == 0) {
// found a match
*type = kMediaTypes[i].subtypes[j].subtype;
return true;
}
}
}
memset(&request, 0, sizeof(ifreq));
strcpy(request.ifr_name, name);
return true;
return false;
}
bool
get_address_family(const char* argument, int32& familyIndex)
static bool
get_address_family(const char* argument, int& family)
{
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
if (!strcmp(argument, kFamilies[i].identifiers[j])) {
// found a match
familyIndex = i;
family = kFamilies[i].family;
return true;
}
}
}
// defaults to AF_INET
familyIndex = 0;
family = AF_UNSPEC;
return false;
}
const address_family*
get_address_family(int32 family)
static const address_family*
address_family_for(int family)
{
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
if (kFamilies[i].family == family)
@ -302,70 +198,57 @@ get_address_family(int32 family)
}
/*! Parses the \a argument as network \a address for the specified \a family.
If \a family is \c AF_UNSPEC, \a family will be overwritten with the family
of the successfully parsed address.
*/
bool
parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
parse_address(int& family, const char* argument, BNetworkAddress& address)
{
if (argument == NULL)
return false;
return kFamilies[familyIndex].parse_address(argument, &address);
status_t status = address.SetTo(family, argument, (uint16)0,
B_NO_ADDRESS_RESOLUTION);
if (status != B_OK)
return false;
if (family == AF_UNSPEC) {
// Test if we support the resulting address family
bool supported = false;
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
if (kFamilies[i].family == address.Family()) {
supported = true;
break;
}
}
if (!supported)
return false;
// Take over family from address
family = address.Family();
}
return true;
}
bool
prefix_length_to_mask(int32 familyIndex, const char* argument,
struct sockaddr& mask)
prefix_length_to_mask(int family, const char* argument, BNetworkAddress& mask)
{
char *end;
uint32 prefixLength = strtoul(argument, &end, 10);
if (end == argument)
return false;
BNetworkAddress address;
if (address.SetToMask(kFamilies[familyIndex].family, prefixLength) != B_OK)
return false;
memcpy(&mask, &address.SockAddr(), address.Length());
return true;
return mask.SetToMask(family, prefixLength) == B_OK;
}
// #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
list_interface_addresses(BNetworkInterface& interface, uint32 flags)
{
@ -376,7 +259,7 @@ list_interface_addresses(BNetworkInterface& interface, uint32 flags)
break;
const address_family* family
= get_address_family(address.Address().Family());
= address_family_for(address.Address().Family());
printf("\t%s addr: %s", family->name,
address.Address().ToString().String());
@ -415,22 +298,10 @@ list_interface(const char* name)
status_t status = interface.GetHardwareAddress(linkAddress);
if (status == B_OK) {
const char *type = "unknown";
char address[256];
strcpy(address, "none");
switch (linkAddress.LinkLevelType()) {
case IFT_ETHER:
{
type = "Ethernet";
if (linkAddress.LinkLevelAddressLength() > 0) {
uint8 *mac = linkAddress.LinkLevelAddress();
sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
} else
strcpy(address, "not available");
break;
}
case IFT_LOOP:
type = "Local Loopback";
break;
@ -439,7 +310,11 @@ list_interface(const char* name)
break;
}
printf("Hardware Type: %s, Address: %s\n", type, address);
BString address = linkAddress.ToString();
if (address.Length() == 0)
address = "none";
printf("Hardware Type: %s, Address: %s\n", type, address.String());
} else
printf("No link level: %s\n", strerror(status));
@ -562,45 +437,33 @@ list_interfaces(const char* name)
void
delete_interface(const char* name, char* const* args, int32 argCount)
{
ifreq request;
if (!prepare_request(request, name))
return;
BNetworkInterface interface(name);
for (int32 i = 0; i < argCount; i++) {
int32 familyIndex;
if (get_address_family(args[i], familyIndex))
int family;
if (get_address_family(args[i], family))
i++;
// TODO: be smart enough to detect the family by the address
int socket = find_socket(request, kFamilies[familyIndex].family);
if (socket == -1) {
fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
kProgramName, kFamilies[familyIndex].name);
exit(1);
}
if (!parse_address(familyIndex, args[i], request.ifr_addr)) {
BNetworkAddress address;
if (!parse_address(family, args[i], address)) {
fprintf(stderr, "%s: Could not parse address \"%s\".\n",
kProgramName, args[i]);
exit(1);
}
if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
status_t status = interface.RemoveAddress(address);
if (status != B_OK) {
fprintf(stderr, "%s: Could not delete address %s from interface %s:"
" %s\n", kProgramName, args[i], name, strerror(errno));
" %s\n", kProgramName, args[i], name, strerror(status));
}
}
if (argCount == 0) {
// Delete interface
int socket = find_socket(request, -1);
if (socket < 0)
exit(1);
request.ifr_addr.sa_family = AF_UNSPEC;
if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
BNetworkRoster& roster = BNetworkRoster::Default();
status_t status = roster.RemoveInterface(interface);
if (status != B_OK) {
fprintf(stderr, "%s: Could not delete interface %s: %s\n",
kProgramName, name, strerror(errno));
}
@ -612,109 +475,95 @@ void
configure_interface(const char* name, char* const* args,
int32 argCount)
{
ifreq request;
if (!prepare_request(request, name))
return;
// try to parse address family
int32 familyIndex;
int family;
int32 i = 0;
if (get_address_family(args[i], familyIndex))
if (get_address_family(args[i], family))
i++;
int socket = sAddressFamilySockets[familyIndex];
if (socket < 0) {
fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
kProgramName, kFamilies[familyIndex].name);
exit(1);
// try to parse address
BNetworkAddress address;
BNetworkAddress mask;
if (parse_address(family, args[i], address)) {
i++;
if (parse_address(family, args[i], mask))
i++;
}
uint32 index = 0;
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
index = request.ifr_index;
bool hasAddress = false, hasMask = false, hasPeer = false;
bool hasBroadcast = false, doAutoConfig = false;
struct sockaddr address, mask, peer, broadcast;
int mtu = -1, metric = -1, media = -1;
int addFlags = 0, currentFlags = 0, removeFlags = 0;
if (index == 0) {
BNetworkInterface interface(name);
if (!interface.Exists()) {
// the interface does not exist yet, we have to add it first
ifaliasreq request;
memset(&request, 0, sizeof(ifaliasreq));
strlcpy(request.ifra_name, name, IF_NAMESIZE);
if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
BNetworkRoster& roster = BNetworkRoster::Default();
status_t status = roster.AddInterface(interface);
if (status != B_OK) {
fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
strerror(errno));
strerror(status));
exit(1);
}
}
// try to parse address
if (parse_address(familyIndex, args[i], address)) {
hasAddress = true;
i++;
if (parse_address(familyIndex, args[i], mask)) {
hasMask = true;
i++;
}
}
BNetworkAddress broadcast;
BNetworkAddress peer;
int mtu = -1, metric = -1, media = -1;
int addFlags = 0, currentFlags = 0, removeFlags = 0;
bool doAutoConfig = false;
// parse parameters and flags
while (i < argCount) {
if (!strcmp(args[i], "peer")) {
if (!parse_address(familyIndex, args[i + 1], peer)) {
if (!parse_address(family, args[i + 1], peer)) {
fprintf(stderr, "%s: Option 'peer' needs valid address "
"parameter\n", kProgramName);
exit(1);
}
hasPeer = true;
i++;
} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
if (hasMask) {
if (!mask.IsEmpty()) {
fprintf(stderr, "%s: Netmask or prefix length is specified "
"twice\n", kProgramName);
exit(1);
}
if (!parse_address(familyIndex, args[i + 1], mask)) {
if (!parse_address(family, args[i + 1], mask)) {
fprintf(stderr, "%s: Option 'netmask' needs valid address "
"parameter\n", kProgramName);
exit(1);
}
hasMask = true;
i++;
} else if (!strcmp(args[i], "prefixlen")
|| !strcmp(args[i], "plen")) {
if (hasMask) {
} else if (!strcmp(args[i], "prefixlen") || !strcmp(args[i], "plen")
|| !strcmp(args[i], "prefix-length")) {
if (!mask.IsEmpty()) {
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);
// default to AF_INET if no address family has been specified yet
if (family == AF_UNSPEC)
family = AF_INET;
if (!prefix_length_to_mask(family, args[i + 1], mask)) {
fprintf(stderr, "%s: Option 'prefix-length %s' is invalid for "
"this address family\n", kProgramName, args[i + 1]);
exit(1);
}
hasMask = true;
i++;
} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
if (hasBroadcast) {
if (!broadcast.IsEmpty()) {
fprintf(stderr, "%s: broadcast address is specified twice\n",
kProgramName);
exit(1);
}
if (!parse_address(familyIndex, args[i + 1], broadcast)) {
if (!parse_address(family, args[i + 1], broadcast)) {
fprintf(stderr, "%s: Option 'broadcast' needs valid address "
"parameter\n", kProgramName);
exit(1);
}
hasBroadcast = true;
addFlags |= IFF_BROADCAST;
i++;
} else if (!strcmp(args[i], "mtu")) {
@ -734,8 +583,8 @@ configure_interface(const char* name, char* const* args,
metric = strtol(args[i + 1], NULL, 0);
i++;
} else if (!strcmp(args[i], "media")) {
if (ioctl(socket, SIOCGIFMEDIA, &request,
sizeof(struct ifreq)) < 0) {
media = interface.Media();
if (media < 0) {
fprintf(stderr, "%s: Unable to detect media type\n",
kProgramName);
exit(1);
@ -745,8 +594,7 @@ configure_interface(const char* name, char* const* args,
kProgramName);
exit(1);
}
if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media),
&media)) {
if (!media_parse_subtype(args[i + 1], IFM_TYPE(media), &media)) {
fprintf(stderr, "%s: Invalid parameter for option 'media': "
"'%s'\n", kProgramName, args[i + 1]);
exit(1);
@ -783,96 +631,71 @@ configure_interface(const char* name, char* const* args,
exit(1);
}
if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) {
if (doAutoConfig && (!address.IsEmpty() || !mask.IsEmpty()
|| !broadcast.IsEmpty() || !peer.IsEmpty())) {
fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName);
exit(1);
}
// set address/mask/broadcast/peer
if (hasAddress) {
memcpy(&request.ifr_addr, &address, address.sa_len);
if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()) {
BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(address);
interfaceAddress.SetMask(mask);
if (!broadcast.IsEmpty())
interfaceAddress.SetBroadcast(broadcast);
else if (!peer.IsEmpty())
interfaceAddress.SetDestination(peer);
if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
status_t status = interface.SetAddress(interfaceAddress);
if (status != B_OK) {
fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
strerror(errno));
strerror(status));
exit(1);
}
}
if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName,
strerror(errno));
exit(1);
}
currentFlags = request.ifr_flags;
if (hasMask) {
memcpy(&request.ifr_mask, &mask, mask.sa_len);
if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting subnet mask failed: %s\n",
kProgramName, strerror(errno));
exit(1);
}
}
if (hasBroadcast) {
memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting broadcast address failed: %s\n",
kProgramName, strerror(errno));
exit(1);
}
}
if (hasPeer) {
memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting peer address failed: %s\n",
kProgramName, strerror(errno));
exit(1);
}
}
currentFlags = interface.Flags();
// set flags
if (hasAddress || hasMask || hasBroadcast || hasPeer)
if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()
|| !peer.IsEmpty())
removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;
if (addFlags || removeFlags) {
request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
status_t status
= interface.SetFlags((currentFlags & ~removeFlags) | addFlags);
if (status != B_OK) {
fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
strerror(errno));
strerror(status));
}
}
// set options
if (mtu != -1) {
request.ifr_mtu = mtu;
if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) {
status_t status = interface.SetMTU(mtu);
if (status != B_OK) {
fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
strerror(errno));
strerror(status));
}
}
if (metric != -1) {
request.ifr_metric = metric;
if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) {
status_t status = interface.SetMetric(metric);
if (status != B_OK) {
fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
strerror(errno));
strerror(status));
}
}
if (media != -1) {
request.ifr_media = media;
if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) {
status_t status = interface.SetMedia(media);
if (status != B_OK) {
fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
strerror(errno));
strerror(status));
}
}
@ -882,7 +705,7 @@ configure_interface(const char* name, char* const* args,
BMessage message(kMsgConfigureInterface);
message.AddString("device", name);
BMessage address;
address.AddString("family", kFamilies[familyIndex].name);
address.AddString("family", address_family_for(family)->name);
address.AddBool("auto_config", true);
message.AddMessage("address", &address);
@ -915,11 +738,13 @@ main(int argc, char** argv)
if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
usage(0);
if (!initialize_address_families()) {
int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
if (socket < 0) {
fprintf(stderr, "%s: The networking stack doesn't seem to be "
"available.\n", kProgramName);
return 1;
}
close(socket);
if (argc > 1
&& (!strcmp(argv[1], "--delete")