aboutgitcodebugslistschat
path: root/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'conf.c')
-rw-r--r--conf.c448
1 files changed, 132 insertions, 316 deletions
diff --git a/conf.c b/conf.c
index e020417..6399fbb 100644
--- a/conf.c
+++ b/conf.c
@@ -17,7 +17,6 @@
#include <getopt.h>
#include <string.h>
#include <errno.h>
-#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -38,6 +37,8 @@
#include "passt.h"
#include "udp.h"
#include "tcp.h"
+#include "netlink.h"
+#include "pasta.h"
/**
* get_bound_ports() - Get maps of ports with bound sockets
@@ -267,301 +268,6 @@ overlap:
}
/**
- * nl_req() - Send netlink request and read response, doesn't return on failure
- * @buf: Buffer for response (BUFSIZ long)
- * @req: Request with netlink header
- * @len: Request length
- */
-static void nl_req(char *buf, void *req, ssize_t len)
-{
- int s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE), v = 1;
- struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };
-
- if (s < 0 ||
- setsockopt(s, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &v, sizeof(v)) ||
- bind(s, (struct sockaddr *)&addr, sizeof(addr)) ||
- (send(s, req, len, 0) < len) ||
- (recv(s, buf, BUFSIZ, 0) < 0)) {
- perror("netlink recv");
- exit(EXIT_FAILURE);
- }
-
- close(s);
-}
-
-/**
- * get_routes() - Get default route and fill in routable interface name
- * @c: Execution context
- */
-static void get_routes(struct ctx *c)
-{
- struct { struct nlmsghdr nlh; struct rtmsg rtm; } req = {
- .nlh.nlmsg_type = RTM_GETROUTE,
- .nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_EXCL,
- .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
- .nlh.nlmsg_seq = 1,
- .rtm.rtm_family = AF_INET,
- .rtm.rtm_table = RT_TABLE_MAIN,
- .rtm.rtm_scope = RT_SCOPE_UNIVERSE,
- .rtm.rtm_type = RTN_UNICAST,
- };
- char ifn[IFNAMSIZ], buf[BUFSIZ];
- struct nlmsghdr *nh;
- struct rtattr *rta;
- struct rtmsg *rtm;
- int n, na, v4, v6;
-
- if (!c->v4 && !c->v6)
- v4 = v6 = -1;
- else
- v6 = -!(v4 = -c->v4);
-
-v6:
- nl_req(buf, &req, sizeof(req));
- nh = (struct nlmsghdr *)buf;
-
- for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
- rtm = (struct rtmsg *)NLMSG_DATA(nh);
-
- if (rtm->rtm_dst_len ||
- (rtm->rtm_family != AF_INET && rtm->rtm_family != AF_INET6))
- continue;
-
- /* Filter on interface only if already given */
- if (*c->ifn) {
- *ifn = 0;
- for (rta = (struct rtattr *)RTM_RTA(rtm),
- na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != RTA_OIF)
- continue;
-
- if_indextoname(*(unsigned *)RTA_DATA(rta), ifn);
- break;
- }
-
- if (strcmp(ifn, c->ifn))
- goto next;
- }
-
- for (rta = (struct rtattr *)RTM_RTA(rtm), na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (!*c->ifn && rta->rta_type == RTA_OIF)
- if_indextoname(*(unsigned *)RTA_DATA(rta), ifn);
-
- if (v4 && rta->rta_type == RTA_GATEWAY &&
- rtm->rtm_family == AF_INET) {
- if (!c->gw4) {
- memcpy(&c->gw4, RTA_DATA(rta),
- sizeof(c->gw4));
- }
- v4 = 1;
- }
-
- if (v6 && rta->rta_type == RTA_GATEWAY &&
- rtm->rtm_family == AF_INET6) {
- if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6)) {
- memcpy(&c->gw6, RTA_DATA(rta),
- sizeof(c->gw6));
- }
- v6 = 1;
- }
- }
-
-next:
- if (nh->nlmsg_type == NLMSG_DONE)
- break;
- }
-
- if (v6 < 0 && req.rtm.rtm_family == AF_INET) {
- req.rtm.rtm_family = AF_INET6;
- req.nlh.nlmsg_seq++;
- goto v6;
- } else if (v6 < 0) {
- v6 = 0;
- }
-
- if ((v4 <= 0 && v6 <= 0) || (!*c->ifn && !*ifn)) {
- err("No routing information");
- exit(EXIT_FAILURE);
- }
-
- if (!*c->ifn)
- strncpy(c->ifn, ifn, IFNAMSIZ);
- c->v4 = v4;
- c->v6 = v6;
-}
-
-/**
- * get_l3_addrs() - Fetch IP addresses of external routable interface
- * @c: Execution context
- */
-static void get_l3_addrs(struct ctx *c)
-{
- struct { struct nlmsghdr nlh; struct ifaddrmsg ifa; } req = {
- .nlh.nlmsg_type = RTM_GETADDR,
- .nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
- .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
- .nlh.nlmsg_seq = 1,
- .ifa.ifa_family = AF_INET,
- .ifa.ifa_index = if_nametoindex(c->ifn),
- };
- struct ifaddrmsg *ifa;
- struct nlmsghdr *nh;
- struct rtattr *rta;
- int n, na, v4, v6;
- char buf[BUFSIZ];
-
- if (c->v4) {
- v4 = -1;
- if ((c->addr4_seen = c->addr4))
- v4 = 1;
- }
-
- if (c->v6) {
- v6 = -2;
- if (!IN6_IS_ADDR_UNSPECIFIED(&c->addr6)) {
- memcpy(&c->addr6_seen, &c->addr6, sizeof(c->addr6));
- memcpy(&c->addr6_ll_seen, &c->addr6, sizeof(c->addr6));
- v6 = -1;
- }
- }
-
-next_v:
- if (v4 < 0)
- req.ifa.ifa_family = AF_INET;
- else if (v6 < 0)
- req.ifa.ifa_family = AF_INET6;
- else
- goto mask_only;
-
- nl_req(buf, &req, sizeof(req));
- nh = (struct nlmsghdr *)buf;
-
- for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
- if (nh->nlmsg_type != RTM_NEWADDR)
- goto next;
-
- ifa = (struct ifaddrmsg *)NLMSG_DATA(nh);
-
- for (rta = (struct rtattr *)IFA_RTA(ifa), na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != IFA_ADDRESS)
- continue;
-
- if (v4 < 0) {
- memcpy(&c->addr4, RTA_DATA(rta),
- sizeof(c->addr4));
- memcpy(&c->addr4_seen, RTA_DATA(rta),
- sizeof(c->addr4_seen));
- v4 = 1;
- } else if (v6 < 0) {
- if (v6 == -2 &&
- ifa->ifa_scope == RT_SCOPE_UNIVERSE) {
- memcpy(&c->addr6, RTA_DATA(rta),
- sizeof(c->addr6));
- memcpy(&c->addr6_seen, RTA_DATA(rta),
- sizeof(c->addr6_seen));
- memcpy(&c->addr6_ll_seen, RTA_DATA(rta),
- sizeof(c->addr6_ll_seen));
- } else if (ifa->ifa_scope == RT_SCOPE_LINK) {
- memcpy(&c->addr6_ll, RTA_DATA(rta),
- sizeof(c->addr6_ll));
- }
- if (!IN6_IS_ADDR_UNSPECIFIED(&c->addr6) &&
- !IN6_IS_ADDR_UNSPECIFIED(&c->addr6_ll))
- v6 = 1;
- }
- }
-next:
- if (nh->nlmsg_type == NLMSG_DONE)
- break;
- }
-
- if (v4 >= 0 && v6 < 0)
- goto next_v;
-
- if (v4 < c->v4 || v6 < c->v6)
- goto out;
-
-mask_only:
- if (v4 && !c->mask4) {
- if (IN_CLASSA(ntohl(c->addr4)))
- c->mask4 = htonl(IN_CLASSA_NET);
- else if (IN_CLASSB(ntohl(c->addr4)))
- c->mask4 = htonl(IN_CLASSB_NET);
- else if (IN_CLASSC(ntohl(c->addr4)))
- c->mask4 = htonl(IN_CLASSC_NET);
- else
- c->mask4 = 0xffffffff;
- }
-
- return;
-out:
- err("Couldn't get addresses for routable interface");
- exit(EXIT_FAILURE);
-}
-
-/**
- * get_l2_addr() - Fetch hardware addresses of external routable interface
- * @c: Execution context
- */
-static void get_l2_addr(struct ctx *c)
-{
- struct { struct nlmsghdr nlh; struct ifinfomsg ifi; } req = {
- .nlh.nlmsg_type = RTM_GETLINK,
- .nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP_FILTERED,
- .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
- .nlh.nlmsg_seq = 1,
- .ifi.ifi_family = AF_UNSPEC,
- .ifi.ifi_index = if_nametoindex(c->ifn),
- };
- struct ifinfomsg *ifi;
- struct nlmsghdr *nh;
- struct rtattr *rta;
- char buf[BUFSIZ];
- int n, na;
-
- if (memcmp(c->mac, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
- goto mac_guest;
-
- nl_req(buf, &req, sizeof(req));
- nh = (struct nlmsghdr *)buf;
-
- for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
- if (nh->nlmsg_type != RTM_NEWLINK)
- goto next;
-
- ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
-
- for (rta = (struct rtattr *)IFLA_RTA(ifi), na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != IFLA_ADDRESS)
- continue;
-
- memcpy(c->mac, RTA_DATA(rta), ETH_ALEN);
- break;
- }
-next:
- if (nh->nlmsg_type == NLMSG_DONE)
- break;
- }
-
- if (!memcmp(c->mac, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
- goto out;
-
-mac_guest:
- if (memcmp(c->mac_guest, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
- memset(&c->mac_guest, 0xff, sizeof(c->mac_guest));
-
- return;
-
-out:
- err("Couldn't get hardware address for routable interface");
- exit(EXIT_FAILURE);
-}
-
-/**
* get_dns() - Get nameserver addresses from local /etc/resolv.conf
* @c: Execution context
*/
@@ -731,6 +437,91 @@ static int conf_ns_opt(struct ctx *c,
}
/**
+ * conf_ip() - Verify or detect IPv4/IPv6 support, get relevant addresses
+ * @c: Execution context
+ */
+static void conf_ip(struct ctx *c)
+{
+ int v4, v6;
+
+ if (c->v4) {
+ c->v4 = IP_VERSION_ENABLED;
+ v4 = IP_VERSION_PROBE;
+ v6 = c->v6 = IP_VERSION_DISABLED;
+ } else if (c->v6) {
+ c->v6 = IP_VERSION_ENABLED;
+ v6 = IP_VERSION_PROBE;
+ v4 = c->v4 = IP_VERSION_DISABLED;
+ } else {
+ c->v4 = c->v6 = IP_VERSION_ENABLED;
+ v4 = v6 = IP_VERSION_PROBE;
+ }
+
+ if (!c->ifi)
+ c->ifi = nl_get_ext_if(&v4, &v6);
+
+ if (v4 != IP_VERSION_DISABLED) {
+ if (!c->gw4)
+ nl_route(0, c->ifi, AF_INET, &c->gw4);
+
+ if (!c->addr4) {
+ nl_addr(0, c->ifi, AF_INET, &c->addr4, 0, NULL);
+ if (!c->mask4) {
+ if (IN_CLASSA(ntohl(c->addr4)))
+ c->mask4 = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ntohl(c->addr4)))
+ c->mask4 = htonl(IN_CLASSB_NET);
+ else if (IN_CLASSC(ntohl(c->addr4)))
+ c->mask4 = htonl(IN_CLASSC_NET);
+ else
+ c->mask4 = 0xffffffff;
+ }
+ }
+
+ memcpy(&c->addr4_seen, &c->addr4, sizeof(c->addr4_seen));
+
+ if (!memcmp(c->mac, MAC_ZERO, ETH_ALEN))
+ nl_link(0, c->ifi, c->mac, 0);
+ }
+
+ if (c->mode == MODE_PASST)
+ memset(&c->mac_guest, 0xff, sizeof(c->mac_guest));
+
+ if (v6 != IP_VERSION_DISABLED) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6))
+ nl_route(0, c->ifi, AF_INET6, &c->gw6);
+
+ nl_addr(0, c->ifi, AF_INET6,
+ IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ? &c->addr6 : NULL,
+ 0, &c->addr6_ll);
+
+ memcpy(&c->addr6_seen, &c->addr6, sizeof(c->addr4_seen));
+ memcpy(&c->addr6_ll_seen, &c->addr6, sizeof(c->addr4_seen));
+ }
+
+ if (!c->gw4 || !c->addr4 ||
+ !memcmp(c->mac, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
+ v4 = IP_VERSION_DISABLED;
+ else
+ v4 = IP_VERSION_ENABLED;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6) ||
+ IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ||
+ IN6_IS_ADDR_UNSPECIFIED(&c->addr6_ll))
+ v6 = IP_VERSION_DISABLED;
+ else
+ v6 = IP_VERSION_ENABLED;
+
+ if ((v4 == IP_VERSION_DISABLED) && (v6 == IP_VERSION_DISABLED)) {
+ err("External interface not usable");
+ exit(EXIT_FAILURE);
+ }
+
+ c->v4 = v4;
+ c->v6 = v6;
+}
+
+/**
* usage() - Print usage and exit
* @name: Executable name
*/
@@ -868,20 +659,22 @@ pasta_opts:
info( " implied if PATH or NAME are given without --userns");
info( " --nsrun-dir Directory for nsfs mountpoints");
info( " default: " NETNS_RUN_DIR);
+ info( " --config-net Configure tap interface in namespace");
+ info( " --ns-mac-addr ADDR Set MAC address on tap interface");
exit(EXIT_FAILURE);
}
void conf_print(struct ctx *c)
{
- char buf6[INET6_ADDRSTRLEN], buf4[INET_ADDRSTRLEN];
+ char buf6[INET6_ADDRSTRLEN], buf4[INET_ADDRSTRLEN], ifn[IFNAMSIZ];
int i;
if (c->mode == MODE_PASTA) {
info("Outbound interface: %s, namespace interface: %s",
- c->ifn, c->pasta_ifn);
+ if_indextoname(c->ifi, ifn), c->pasta_ifn);
} else {
- info("Outbound interface: %s", c->ifn);
+ info("Outbound interface: %s", if_indextoname(c->ifi, ifn));
}
if (c->v4) {
@@ -991,6 +784,8 @@ void conf(struct ctx *c, int argc, char **argv)
{"userns", required_argument, NULL, 2 },
{"netns-only", no_argument, &c->netns_only, 1 },
{"nsrun-dir", required_argument, NULL, 3 },
+ {"config-net", no_argument, &c->pasta_conf_ns, 1 },
+ {"ns-mac-addr", required_argument, NULL, 4 },
{ 0 },
};
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
@@ -1051,6 +846,22 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]);
}
break;
+ case 4:
+ if (c->mode != MODE_PASTA) {
+ err("--ns-mac-addr is for pasta mode only");
+ usage(argv[0]);
+ }
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ errno = 0;
+ b = strtol(optarg + i * 3, NULL, 16);
+ if (b < 0 || b > UCHAR_MAX || errno) {
+ err("Invalid MAC address: %s", optarg);
+ usage(argv[0]);
+ }
+ c->mac_guest[i] = b;
+ }
+ break;
case 'd':
if (c->debug) {
err("Multiple --debug options given");
@@ -1217,12 +1028,16 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]);
break;
case 'i':
- if (*c->ifn) {
+ if (c->ifi) {
err("Redundant interface: %s", optarg);
usage(argv[0]);
}
- strncpy(c->ifn, optarg, IFNAMSIZ - 1);
+ if (!(c->ifi = if_nametoindex(optarg))) {
+ err("Invalid interface name %s: %s", optarg,
+ strerror(errno));
+ usage(argv[0]);
+ }
break;
case 'D':
if (c->no_dns ||
@@ -1320,25 +1135,26 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]);
}
- if (c->v4 || c->v6) {
- if (!c->v4)
- c->no_dhcp = 1;
+ if (c->mode == MODE_PASTA && !c->pasta_netns_fd)
+ pasta_start_ns(c);
- if (!c->v6) {
- c->no_ndp = 1;
- c->no_dhcpv6 = 1;
- }
+ if (nl_sock_init(c)) {
+ err("Failed to get netlink socket");
+ exit(EXIT_FAILURE);
}
- if (!c->mtu) {
- c->mtu = (ETH_MAX_MTU - ETH_HLEN) /
- sizeof(uint32_t) * sizeof(uint32_t);
+ conf_ip(c);
+
+ if (!c->v4)
+ c->no_dhcp = 1;
+
+ if (!c->v6) {
+ c->no_ndp = 1;
+ c->no_dhcpv6 = 1;
}
- get_routes(c);
- get_l3_addrs(c);
- if (c->v4)
- get_l2_addr(c);
+ if (!c->mtu)
+ c->mtu = ROUND_DOWN(ETH_MAX_MTU - ETH_HLEN, sizeof(uint32_t));
if (c->mode == MODE_PASTA && dns4 == c->dns4 && dns6 == c->dns6)
c->no_dns = 1;
@@ -1347,7 +1163,7 @@ void conf(struct ctx *c, int argc, char **argv)
get_dns(c);
if (!*c->pasta_ifn)
- strncpy(c->pasta_ifn, c->ifn, IFNAMSIZ);
+ if_indextoname(c->ifi, c->pasta_ifn);
#ifdef PASST_LEGACY_NO_OPTIONS
if (c->mode == MODE_PASST) {