* The net_server now accepts messages from the outside that want to configure

an interface (I don't remember why I didn't want this earlier, but well).
* ifconfig now has an auto-config option that will trigger DHCP.
* Also, it will now remove the IFF_AUTO_CONFIGURED and IFF_CONFIGURING flags
  if an address is specified (any on-going auto-configuration should check for
  these and abort if they aren't there anymore).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28831 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-12-28 22:18:21 +00:00
parent 74ff314b2f
commit fd95a7e124
4 changed files with 122 additions and 51 deletions
+4 -2
View File
@@ -6,9 +6,11 @@ if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
# Unfortunately we get more than we want, namely all POSIX headers. # Unfortunately we get more than we want, namely all POSIX headers.
} }
UseHeaders [ FDirName $(HAIKU_TOP) src servers net ] : true ;
BinCommand ifconfig : BinCommand ifconfig :
ifconfig.cpp ifconfig.cpp
: libnetwork.so : be network
; ;
# Installation -- in the test directory for the time being # Installation -- in the test directory for the time being
@@ -16,7 +18,7 @@ HaikuInstall install-networking
: [ FDirName $(HAIKU_TEST_DIR) kits net ] : [ FDirName $(HAIKU_TEST_DIR) kits net ]
: ifconfig ; : ifconfig ;
HaikuInstall install-userland-networking HaikuInstall install-userland-networking
: [ FDirName $(HAIKU_TEST_DIR) kits net userland ] : [ FDirName $(HAIKU_TEST_DIR) kits net userland ]
: ifconfig : ifconfig
: installed-userland-networking : installed-userland-networking
+99 -36
View File
@@ -8,7 +8,8 @@
*/ */
#include <SupportDefs.h> #include <Message.h>
#include <Messenger.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/if.h> #include <net/if.h>
@@ -25,6 +26,8 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <NetServer.h>
extern const char* __progname; extern const char* __progname;
const char* kProgramName = __progname; const char* kProgramName = __progname;
@@ -63,7 +66,7 @@ inet_parse_address(const char* string, sockaddr* _address)
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;
address.sin_addr = inetAddress; address.sin_addr = inetAddress;
@@ -77,7 +80,7 @@ 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;
@@ -153,7 +156,7 @@ media_parse_subtype(const char* string, int media, int* type)
{ {
for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
// only check for generic or correct subtypes // only check for generic or correct subtypes
if (kMediaTypes[i].type && if (kMediaTypes[i].type &&
kMediaTypes[i].type != media) kMediaTypes[i].type != media)
continue; continue;
for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
@@ -174,7 +177,8 @@ media_parse_subtype(const char* string, int media, int* type)
void void
usage(int status) usage(int status)
{ {
printf("usage: %s [<interface> [<address family>] [<address> [<mask>]] [<option/flags>...]]\n" printf("usage: %s [<interface> [<address family>] [<address> [<mask>] | "
"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"
@@ -190,7 +194,10 @@ usage(int status)
printf("%s ", kMediaTypes[i].subtypes[j].name); printf("%s ", kMediaTypes[i].subtypes[j].name);
printf("\n"); printf("\n");
} }
printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, loopback\n\n" printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, "
"loopback\n"
"If you specify \"auto-config\" instead of an address, it will be "
"configured automatically.\n\n"
"Example:\n" "Example:\n"
"\t%s loop 127.0.0.1 255.0.0.0 up\n", "\t%s loop 127.0.0.1 255.0.0.0 up\n",
kProgramName); kProgramName);
@@ -316,7 +323,7 @@ list_interface(int socket, const char* name)
if (IFM_TYPE(request.ifr_media) == 0/*IFT_LOOP*/) if (IFM_TYPE(request.ifr_media) == 0/*IFT_LOOP*/)
break; break;
// only check for generic or correct subtypes // only check for generic or correct subtypes
if (kMediaTypes[i].type && if (kMediaTypes[i].type &&
kMediaTypes[i].type != IFM_TYPE(request.ifr_media)) kMediaTypes[i].type != IFM_TYPE(request.ifr_media))
continue; continue;
for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
@@ -497,10 +504,11 @@ configure_interface(int socket, const char* name, char* const* args,
if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
index = request.ifr_index; index = request.ifr_index;
bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false; bool hasAddress = false, hasMask = false, hasPeer = false;
bool hasBroadcast = false, doAutoConfig = false;
struct sockaddr address, mask, peer, broadcast; struct sockaddr address, mask, peer, broadcast;
int mtu = -1, metric = -1, media = -1; int mtu = -1, metric = -1, media = -1;
int addFlags = 0, removeFlags = 0, currentFlags = 0; int addFlags = 0, currentFlags = 0, removeFlags = 0;
// try to parse address family // try to parse address family
@@ -552,8 +560,8 @@ configure_interface(int socket, const char* name, char* const* args,
while (i < argCount) { while (i < argCount) {
if (!strcmp(args[i], "peer")) { if (!strcmp(args[i], "peer")) {
if (!parse_address(familyIndex, args[i + 1], peer)) { if (!parse_address(familyIndex, args[i + 1], peer)) {
fprintf(stderr, "%s: Option 'peer' needs valid address parameter\n", fprintf(stderr, "%s: Option 'peer' needs valid address "
kProgramName); "parameter\n", kProgramName);
exit(1); exit(1);
} }
hasPeer = true; hasPeer = true;
@@ -565,8 +573,8 @@ configure_interface(int socket, const char* name, char* const* args,
exit(1); exit(1);
} }
if (!parse_address(familyIndex, args[i + 1], mask)) { if (!parse_address(familyIndex, args[i + 1], mask)) {
fprintf(stderr, "%s: Option 'netmask' needs valid address parameter\n", fprintf(stderr, "%s: Option 'netmask' needs valid address "
kProgramName); "parameter\n", kProgramName);
exit(1); exit(1);
} }
hasMask = true; hasMask = true;
@@ -578,8 +586,8 @@ configure_interface(int socket, const char* name, char* const* args,
exit(1); exit(1);
} }
if (!parse_address(familyIndex, args[i + 1], broadcast)) { if (!parse_address(familyIndex, args[i + 1], broadcast)) {
fprintf(stderr, "%s: Option 'broadcast' needs valid address parameter\n", fprintf(stderr, "%s: Option 'broadcast' needs valid address "
kProgramName); "parameter\n", kProgramName);
exit(1); exit(1);
} }
hasBroadcast = true; hasBroadcast = true;
@@ -588,8 +596,8 @@ configure_interface(int socket, const char* name, char* const* args,
} else if (!strcmp(args[i], "mtu")) { } else if (!strcmp(args[i], "mtu")) {
mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0; mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
if (mtu <= 500) { if (mtu <= 500) {
fprintf(stderr, "%s: Option 'mtu' expected valid max transfer unit size\n", fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
kProgramName); "unit size\n", kProgramName);
exit(1); exit(1);
} }
i++; i++;
@@ -602,7 +610,8 @@ configure_interface(int socket, const char* name, char* const* args,
metric = strtol(args[i + 1], NULL, 0); metric = strtol(args[i + 1], NULL, 0);
i++; i++;
} else if (!strcmp(args[i], "media")) { } else if (!strcmp(args[i], "media")) {
if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) < 0) { if (ioctl(socket, SIOCGIFMEDIA, &request,
sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Unable to detect media type\n", fprintf(stderr, "%s: Unable to detect media type\n",
kProgramName); kProgramName);
exit(1); exit(1);
@@ -612,9 +621,10 @@ configure_interface(int socket, const char* name, char* const* args,
kProgramName); kProgramName);
exit(1); exit(1);
} }
if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media), &media)) { if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media),
fprintf(stderr, "%s: Invalid parameter for option 'media': '%s'\n", &media)) {
kProgramName, args[i + 1]); fprintf(stderr, "%s: Invalid parameter for option 'media': "
"'%s'\n", kProgramName, args[i + 1]);
exit(1); exit(1);
} }
i++; i++;
@@ -636,6 +646,8 @@ configure_interface(int socket, const char* name, char* const* args,
removeFlags |= IFF_ALLMULTI; removeFlags |= IFF_ALLMULTI;
} else if (!strcmp(args[i], "loopback")) { } else if (!strcmp(args[i], "loopback")) {
addFlags |= IFF_LOOPBACK; addFlags |= IFF_LOOPBACK;
} else if (!strcmp(args[i], "auto-config")) {
doAutoConfig = true;
} else } else
usage(1); usage(1);
@@ -647,19 +659,26 @@ configure_interface(int socket, const char* name, char* const* args,
exit(1); exit(1);
} }
if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) {
fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName);
exit(1);
}
// set address/mask/broadcast/peer // set address/mask/broadcast/peer
if (hasAddress) { if (hasAddress) {
memcpy(&request.ifr_addr, &address, address.sa_len); memcpy(&request.ifr_addr, &address, address.sa_len);
if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) { if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
strerror(errno));
exit(1); exit(1);
} }
} }
if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) { if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName,
strerror(errno));
exit(1); exit(1);
} }
currentFlags = request.ifr_flags; currentFlags = request.ifr_flags;
@@ -668,7 +687,8 @@ configure_interface(int socket, const char* name, char* const* args,
memcpy(&request.ifr_mask, &mask, mask.sa_len); memcpy(&request.ifr_mask, &mask, mask.sa_len);
if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) { if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting subnet mask failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting subnet mask failed: %s\n",
kProgramName, strerror(errno));
exit(1); exit(1);
} }
} }
@@ -677,7 +697,8 @@ configure_interface(int socket, const char* name, char* const* args,
memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len); memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) { if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting broadcast address failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting broadcast address failed: %s\n",
kProgramName, strerror(errno));
exit(1); exit(1);
} }
} }
@@ -686,37 +707,79 @@ configure_interface(int socket, const char* name, char* const* args,
memcpy(&request.ifr_dstaddr, &peer, peer.sa_len); memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) { if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting peer address failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting peer address failed: %s\n",
kProgramName, strerror(errno));
exit(1); exit(1);
} }
} }
// set flags // set flags
if (hasAddress || hasMask || hasBroadcast || hasPeer) {
removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;
}
printf("set flags: current %x, remove %x, add %x\n", currentFlags, removeFlags, addFlags);
if (addFlags || removeFlags) { if (addFlags || removeFlags) {
request.ifr_flags = (currentFlags & ~removeFlags) | addFlags; request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) printf(" --> set %x\n", request.ifr_flags);
fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, strerror(errno)); if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
strerror(errno));
}
} }
// set options // set options
if (mtu != -1) { if (mtu != -1) {
request.ifr_mtu = mtu; request.ifr_mtu = mtu;
if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
strerror(errno));
}
} }
if (metric != -1) { if (metric != -1) {
request.ifr_metric = metric; request.ifr_metric = metric;
if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
strerror(errno));
}
} }
if (media != -1) { if (media != -1) {
request.ifr_media = media; request.ifr_media = media;
if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) {
fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, strerror(errno)); fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
strerror(errno));
}
}
// start auto configuration, if asked for
if (doAutoConfig) {
BMessage message(kMsgConfigureInterface);
message.AddString("device", name);
BMessage address;
address.AddString("family", "inet");
address.AddBool("auto config", true);
message.AddMessage("address", &address);
BMessenger networkServer(kNetServerSignature);
if (networkServer.IsValid()) {
BMessage reply;
status_t status = networkServer.SendMessage(&message, &reply);
if (status != B_OK) {
fprintf(stderr, "%s: Sending auto-config message failed: %s\n",
kProgramName, strerror(status));
} else if (reply.FindInt32("status", &status) == B_OK
&& status != B_OK) {
fprintf(stderr, "%s: Auto-configuring failed: %s\n",
kProgramName, strerror(status));
}
} else {
fprintf(stderr, "%s: The net_server needs to run for the auto "
"configuration!\n", kProgramName);
}
} }
} }
@@ -746,8 +809,8 @@ main(int argc, char** argv)
// we need a socket to talk to the networking stack // we need a socket to talk to the networking stack
int socket = ::socket(AF_INET, SOCK_DGRAM, 0); int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0) { if (socket < 0) {
fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n", fprintf(stderr, "%s: The networking stack doesn't seem to be "
kProgramName); "available.\n", kProgramName);
return 1; return 1;
} }
+16 -12
View File
@@ -39,9 +39,6 @@
#include "Settings.h" #include "Settings.h"
static const char *kSignature = "application/x-vnd.haiku-net_server";
typedef std::map<std::string, AutoconfigLooper*> LooperMap; typedef std::map<std::string, AutoconfigLooper*> LooperMap;
@@ -242,7 +239,7 @@ get_mac_address(const char* device, uint8* address)
NetServer::NetServer(status_t& error) NetServer::NetServer(status_t& error)
: BServer(kSignature, false, &error) : BServer(kNetServerSignature, false, &error)
{ {
} }
@@ -306,10 +303,12 @@ NetServer::MessageReceived(BMessage* message)
case kMsgConfigureInterface: case kMsgConfigureInterface:
{ {
#if 0
if (!message->ReturnAddress().IsTargetLocal()) { if (!message->ReturnAddress().IsTargetLocal()) {
// for now, we only accept this message from add-ons // for now, we only accept this message from add-ons
break; break;
} }
#endif
// we need a socket to talk to the networking stack // we need a socket to talk to the networking stack
int socket = ::socket(AF_INET, SOCK_DGRAM, 0); int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
@@ -475,7 +474,8 @@ NetServer::_TestForInterface(int socket, const char* name)
break; break;
} }
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);
@@ -484,7 +484,8 @@ NetServer::_TestForInterface(int socket, const char* name)
status_t status_t
NetServer::_ConfigureInterface(int socket, BMessage& interface, bool fromMessage) NetServer::_ConfigureInterface(int socket, BMessage& interface,
bool fromMessage)
{ {
const char *device; const char *device;
if (interface.FindString("device", &device) != B_OK) if (interface.FindString("device", &device) != B_OK)
@@ -513,8 +514,8 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface, bool fromMessage
metric = -1; metric = -1;
BMessage addressMessage; BMessage addressMessage;
for (int32 index = 0; interface.FindMessage("address", index, &addressMessage) == B_OK; for (int32 index = 0; interface.FindMessage("address", index,
index++) { &addressMessage) == B_OK; index++) {
const char* family; const char* family;
if (addressMessage.FindString("family", &family) < B_OK) if (addressMessage.FindString("family", &family) < B_OK)
continue; continue;
@@ -556,12 +557,15 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface, bool fromMessage
bool autoConfig; bool autoConfig;
if (addressMessage.FindBool("auto config", &autoConfig) != B_OK) if (addressMessage.FindBool("auto config", &autoConfig) != B_OK)
autoConfig = false; autoConfig = false;
#if 0
if (autoConfig && fromMessage) { if (autoConfig && fromMessage) {
// we don't accept auto-config messages this way // we don't accept auto-config messages this way
continue; continue;
} }
#endif
bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false; bool hasAddress = false, hasMask = false, hasPeer = false;
bool hasBroadcast = false;
struct sockaddr address, mask, peer, broadcast, gateway; struct sockaddr address, mask, peer, broadcast, gateway;
const char* string; const char* string;
@@ -794,8 +798,8 @@ NetServer::_BringUpInterfaces()
// we need a socket to talk to the networking stack // we need a socket to talk to the networking stack
int socket = ::socket(AF_INET, SOCK_DGRAM, 0); int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0) { if (socket < 0) {
fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n", fprintf(stderr, "%s: The networking stack doesn't seem to be "
Name()); "available.\n", Name());
Quit(); Quit();
return; return;
} }
@@ -849,7 +853,7 @@ NetServer::_StartServices()
int int
main() main(int argc, char** argv)
{ {
status_t status; status_t status;
NetServer server(status); NetServer server(status);
+3 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -14,6 +14,8 @@
#include <net/if.h> #include <net/if.h>
static const char* kNetServerSignature = "application/x-vnd.haiku-net_server";
static const uint32 kMsgConfigureInterface = 'COif'; static const uint32 kMsgConfigureInterface = 'COif';