示例#1
0
文件: ifconfig.cpp 项目: mariuz/haiku
void
configure_interface(int socket, const char* name, char* const* args,
	int32 argCount)
{
	ifreq request;
	if (!prepare_request(request, name))
		return;

	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;

	// 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) {
		// the interface does not exist yet, we have to add it first
		request.ifr_parameter.base_name[0] = '\0';
		request.ifr_parameter.device[0] = '\0';
		request.ifr_parameter.sub_type = 0;
			// the default device is okay for us

		if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
				strerror(errno));
			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++;
		}
	}

	// parse parameters and flags

	while (i < argCount) {
		if (!strcmp(args[i], "peer")) {
			if (!parse_address(familyIndex, 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) {
				fprintf(stderr, "%s: Netmask is specified twice\n",
					kProgramName);
				exit(1);
			}
			if (!parse_address(familyIndex, 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], "bc") || !strcmp(args[i], "broadcast")) {
			if (hasBroadcast) {
				fprintf(stderr, "%s: broadcast address is specified twice\n",
					kProgramName);
				exit(1);
			}
			if (!parse_address(familyIndex, 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")) {
			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
			if (mtu <= 500) {
				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
					"unit size\n", kProgramName);
				exit(1);
			}
			i++;
		} else if (!strcmp(args[i], "metric")) {
			if (i + 1 >= argCount) {
				fprintf(stderr, "%s: Option 'metric' exptected parameter\n",
					kProgramName);
				exit(1);
			}
			metric = strtol(args[i + 1], NULL, 0);
			i++;
		} else if (!strcmp(args[i], "media")) {
			if (ioctl(socket, SIOCGIFMEDIA, &request,
					sizeof(struct ifreq)) < 0) {
				fprintf(stderr, "%s: Unable to detect media type\n",
					kProgramName);
				exit(1);
			}
			if (i + 1 >= argCount) {
				fprintf(stderr, "%s: Option 'media' exptected parameter\n",
					kProgramName);
				exit(1);
			}
			if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media),
					&media)) {
				fprintf(stderr, "%s: Invalid parameter for option 'media': "
					"'%s'\n", kProgramName, args[i + 1]);
				exit(1);
			}
			i++;
		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
			addFlags |= IFF_UP;
		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
			removeFlags |= IFF_UP;
		} else if (!strcmp(args[i], "bcast")) {
			addFlags |= IFF_BROADCAST;
		} else if (!strcmp(args[i], "-bcast")) {
			removeFlags |= IFF_BROADCAST;
		} else if (!strcmp(args[i], "promisc")) {
			addFlags |= IFF_PROMISC;
		} else if (!strcmp(args[i], "-promisc")) {
			removeFlags |= IFF_PROMISC;
		} else if (!strcmp(args[i], "allmulti")) {
			addFlags |= IFF_ALLMULTI;
		} else if (!strcmp(args[i], "-allmulti")) {
			removeFlags |= IFF_ALLMULTI;
		} else if (!strcmp(args[i], "loopback")) {
			addFlags |= IFF_LOOPBACK;
		} else if (!strcmp(args[i], "auto-config")) {
			doAutoConfig = true;
		} else
			usage(1);

		i++;
	}

	if ((addFlags & removeFlags) != 0) {
		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
		exit(1);
	}

	if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) {
		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 (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
				strerror(errno));
			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);
		}
	}

	// set flags

	if (hasAddress || hasMask || hasBroadcast || hasPeer)
		removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;

	if (addFlags || removeFlags) {
		request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
		if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
				strerror(errno));
		}
	}

	// set options

	if (mtu != -1) {
		request.ifr_mtu = mtu;
		if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) {
			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
				strerror(errno));
		}
	}

	if (metric != -1) {
		request.ifr_metric = metric;
		if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) {
			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
				strerror(errno));
		}
	}

	if (media != -1) {
		request.ifr_media = media;
		if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) {
			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);
		}
	}
}
示例#2
0
void
configure_interface(const char* name, char* const* args, int32 argCount)
{
	// try to parse address family

	int32 i = 0;
	int family = get_address_family(args[i]);
	if (family != AF_UNSPEC)
		i++;

	// try to parse address

	BNetworkAddress address;
	BNetworkAddress mask;

	if (parse_address(family, args[i], address)) {
		i++;

		if (parse_address(family, args[i], mask))
			i++;
	}

	BNetworkInterface interface(name);
	if (!interface.Exists()) {
		// the interface does not exist yet, we have to add it first
		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(status));
			exit(1);
		}
	}

	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(family, args[i + 1], peer)) {
				fprintf(stderr, "%s: Option 'peer' needs valid address "
					"parameter\n", kProgramName);
				exit(1);
			}
			i++;
		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
			if (!mask.IsEmpty()) {
				fprintf(stderr, "%s: Netmask or prefix length is specified "
					"twice\n", kProgramName);
				exit(1);
			}
			if (!parse_address(family, args[i + 1], mask)) {
				fprintf(stderr, "%s: Option 'netmask' needs valid address "
					"parameter\n", kProgramName);
				exit(1);
			}
			i++;
		} 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);
			}

			// 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);
			}
			i++;
		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
			if (!broadcast.IsEmpty()) {
				fprintf(stderr, "%s: broadcast address is specified twice\n",
					kProgramName);
				exit(1);
			}
			if (!parse_address(family, args[i + 1], broadcast)) {
				fprintf(stderr, "%s: Option 'broadcast' needs valid address "
					"parameter\n", kProgramName);
				exit(1);
			}
			addFlags |= IFF_BROADCAST;
			i++;
		} else if (!strcmp(args[i], "mtu")) {
			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
			if (mtu <= 500) {
				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
					"unit size\n", kProgramName);
				exit(1);
			}
			i++;
		} else if (!strcmp(args[i], "metric")) {
			if (i + 1 >= argCount) {
				fprintf(stderr, "%s: Option 'metric' expected parameter\n",
					kProgramName);
				exit(1);
			}
			metric = strtol(args[i + 1], NULL, 0);
			i++;
		} else if (!strcmp(args[i], "media")) {
			media = interface.Media();
			if (media < 0) {
				fprintf(stderr, "%s: Unable to detect media type\n",
					kProgramName);
				exit(1);
			}
			if (i + 1 >= argCount) {
				fprintf(stderr, "%s: Option 'media' expected parameter\n",
					kProgramName);
				exit(1);
			}
			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);
			}
			i++;
		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
			addFlags |= IFF_UP;
		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
			removeFlags |= IFF_UP;
		} else if (!strcmp(args[i], "bcast")) {
			addFlags |= IFF_BROADCAST;
		} else if (!strcmp(args[i], "-bcast")) {
			removeFlags |= IFF_BROADCAST;
		} else if (!strcmp(args[i], "promisc")) {
			addFlags |= IFF_PROMISC;
		} else if (!strcmp(args[i], "-promisc")) {
			removeFlags |= IFF_PROMISC;
		} else if (!strcmp(args[i], "allmulti")) {
			addFlags |= IFF_ALLMULTI;
		} else if (!strcmp(args[i], "-allmulti")) {
			removeFlags |= IFF_ALLMULTI;
		} else if (!strcmp(args[i], "loopback")) {
			addFlags |= IFF_LOOPBACK;
		} else if (!strcmp(args[i], "auto-config")) {
			doAutoConfig = true;
		} else
			usage(1);

		i++;
	}

	if ((addFlags & removeFlags) != 0) {
		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
		exit(1);
	}

	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 (!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);

		status_t status = interface.SetAddress(interfaceAddress);
		if (status != B_OK) {
			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
				strerror(status));
			exit(1);
		}
	}

	currentFlags = interface.Flags();

	// set flags

	if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()
		|| !peer.IsEmpty())
		removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;

	if (addFlags || removeFlags) {
		status_t status
			= interface.SetFlags((currentFlags & ~removeFlags) | addFlags);
		if (status != B_OK) {
			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
				strerror(status));
		}
	}

	// set options

	if (mtu != -1) {
		status_t status = interface.SetMTU(mtu);
		if (status != B_OK) {
			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
				strerror(status));
		}
	}

	if (metric != -1) {
		status_t status = interface.SetMetric(metric);
		if (status != B_OK) {
			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
				strerror(status));
		}
	}

	if (media != -1) {
		status_t status = interface.SetMedia(media);
		if (status != B_OK) {
			fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
				strerror(status));
		}
	}

	// start auto configuration, if asked for

	if (doAutoConfig) {
		status_t status = interface.AutoConfigure(family);
		if (status == B_BAD_PORT_ID) {
			fprintf(stderr, "%s: The net_server needs to run for the auto "
				"configuration!\n", kProgramName);
		} else if (status != B_OK) {
			fprintf(stderr, "%s: Auto-configuring failed: %s\n", kProgramName,
				strerror(status));
		}
	}
}