| From 43875b17a5d2a1cbeaeee2ebc9e1eff4919b000c Mon Sep 17 00:00:00 2001 |
| From: Paul Stewart <pstew@chromium.org> |
| Date: Wed, 13 May 2015 11:09:20 -0700 |
| Subject: [PATCH] dhcpcd: Allow lease file to be set on command line |
| |
| Currently, dhcpcd names its lease files using the interface name |
| as the unique part of the name. There are a couple reasons why |
| this may not work well: firstly if "eth0" can have different MAC |
| addresses (multiple USB-Ethernet dongles for example) leases for |
| one interface aren't valid for the other. Secondly, when using |
| a wireless interface, it would be convenient to hold multiple |
| leases in parallel for each SSID one is connected to. |
| |
| This change adds a suffix to each interface argument (dhcpcd can |
| accept multiple interface arguments) that specifies the identifier |
| to use to save lease files with. By default, the behavior is |
| identical. |
| |
| The second CL (https://gerrit.chromium.org/gerrit/22170) for fixing |
| pid file formating bug originally introduced by this CL is not needed |
| anymore since this bug doesn't exist/apply in the updated implementation. |
| |
| BUG=chromium-os:25717 |
| TEST=Re-run dhcpcd with and without an identifier suffix. |
| |
| Reviewed-on: https://gerrit.chromium.org/gerrit/21991 |
| Reviewed-on: https://gerrit.chromium.org/gerrit/22170 |
| |
| --- |
| dhcp-common.c | 8 ++++++++ |
| dhcp.h | 2 +- |
| dhcpcd.8.in | 6 ++++++ |
| dhcpcd.c | 22 +++++++++++++++----- |
| dhcpcd.h | 2 ++ |
| if.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++------------ |
| if.h | 2 ++ |
| 7 files changed, 88 insertions(+), 19 deletions(-) |
| |
| diff --git a/dhcp-common.c b/dhcp-common.c |
| index 2936b55..39d9787 100644 |
| --- a/dhcp-common.c |
| +++ b/dhcp-common.c |
| @@ -741,6 +741,14 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family, |
| return 0; |
| } |
| |
| + if (strlen(ifp->lease_identifier) > 0) { |
| + /* Only supports lease identifier for IPv4 for now. */ |
| + if (family == AF_INET) { |
| + return snprintf(leasefile, len, LEASEFILE, |
| + ifp->lease_identifier, "", ""); |
| + } |
| + } |
| + |
| switch (family) { |
| case AF_INET: |
| case AF_INET6: |
| diff --git a/dhcp.h b/dhcp.h |
| index acef896..ed94395 100644 |
| --- a/dhcp.h |
| +++ b/dhcp.h |
| @@ -228,7 +228,7 @@ struct dhcp_state { |
| struct in_addr dst; |
| uint8_t added; |
| |
| - char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDSIZE * 4)]; |
| + char leasefile[PATH_MAX]; |
| time_t start_uptime; |
| |
| unsigned char *clientid; |
| diff --git a/dhcpcd.8.in b/dhcpcd.8.in |
| index a67626a..e815620 100644 |
| --- a/dhcpcd.8.in |
| +++ b/dhcpcd.8.in |
| @@ -191,6 +191,12 @@ changes the routes to use the interface with the same route and the lowest |
| metric. |
| See options below for controlling which interfaces we allow and deny through |
| the use of patterns. |
| +.Pp |
| +If an interface name is suffixed by an equal-sign, the text following the |
| +equal sign will be used instead of the interface name as the unique identifier |
| +for the DHCP lease file. Doing so allows the caller to specify different |
| +lease files for the same interface (e.g, when switching the same wireless |
| +interface between different 802.11 networks). |
| .Ss Hooking into events |
| .Nm |
| runs |
| diff --git a/dhcpcd.c b/dhcpcd.c |
| index 9528dc8..763e06f 100644 |
| --- a/dhcpcd.c |
| +++ b/dhcpcd.c |
| @@ -1362,6 +1362,7 @@ main(int argc, char **argv) |
| int sig; |
| const char *siga; |
| #endif |
| + char ifn[IF_NAMESIZE]; |
| |
| /* Test for --help and --version */ |
| if (argc > 1) { |
| @@ -1523,13 +1524,15 @@ main(int argc, char **argv) |
| * instance for that interface. */ |
| if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) { |
| const char *per; |
| - |
| - if (strlen(argv[optind]) > IF_NAMESIZE) { |
| + int intf_len = strlen(argv[optind]); |
| + split_interface_lease(argv[optind], &intf_len, NULL); |
| + if (intf_len > IF_NAMESIZE) { |
| logger(&ctx, LOG_ERR, |
| "%s: interface name too long", |
| argv[optind]); |
| goto exit_failure; |
| } |
| + strlcpy(ifn, argv[optind], intf_len + 1); |
| /* Allow a dhcpcd interface per address family */ |
| switch(family) { |
| case AF_INET: |
| @@ -1542,7 +1545,7 @@ main(int argc, char **argv) |
| per = ""; |
| } |
| snprintf(ctx.pidfile, sizeof(ctx.pidfile), |
| - PIDFILE, "-", argv[optind], per); |
| + PIDFILE, "-", ifn, per); |
| } else { |
| snprintf(ctx.pidfile, sizeof(ctx.pidfile), |
| PIDFILE, "", "", ""); |
| @@ -1780,10 +1783,19 @@ main(int argc, char **argv) |
| goto exit_failure; |
| } |
| for (i = 0; i < ctx.ifc; i++) { |
| - if (if_find(ctx.ifaces, ctx.ifv[i]) == NULL) |
| + int intf_len = strlen(ctx.ifv[i]); |
| + split_interface_lease(ctx.ifv[i], &intf_len, NULL); |
| + if (intf_len > IF_NAMESIZE) { |
| logger(&ctx, LOG_ERR, |
| - "%s: interface not found or invalid", |
| + "%s: interface name too long", |
| ctx.ifv[i]); |
| + continue; |
| + } |
| + strlcpy(ifn, ctx.ifv[i], intf_len + 1); |
| + if (if_find(ctx.ifaces, ifn) == NULL) |
| + logger(&ctx, LOG_ERR, |
| + "%s: interface not found or invalid", |
| + ifn); |
| } |
| if (TAILQ_FIRST(ctx.ifaces) == NULL) { |
| if (ctx.ifc == 0) |
| diff --git a/dhcpcd.h b/dhcpcd.h |
| index 8b34997..ae2b0ce 100644 |
| --- a/dhcpcd.h |
| +++ b/dhcpcd.h |
| @@ -40,6 +40,7 @@ |
| #define IF_SSIDSIZE 33 |
| #define PROFILE_LEN 64 |
| #define SECRET_LEN 64 |
| +#define LEASE_IDENTIFIER_LEN (PATH_MAX - sizeof(LEASEFILE)) |
| |
| #define LINK_UP 1 |
| #define LINK_UNKNOWN 0 |
| @@ -73,6 +74,7 @@ struct interface { |
| int wireless; |
| uint8_t ssid[IF_SSIDSIZE]; |
| unsigned int ssid_len; |
| + char lease_identifier[LEASE_IDENTIFIER_LEN]; |
| |
| char profile[PROFILE_LEN]; |
| struct if_options *options; |
| diff --git a/if.c b/if.c |
| index 2f1a7e5..683021f 100644 |
| --- a/if.c |
| +++ b/if.c |
| @@ -74,6 +74,34 @@ |
| #undef IFLR_ACTIVE |
| #endif |
| |
| +int |
| +split_interface_lease(const char *ifname, int *interface_name_len, |
| + const char **lease_identifier) |
| +{ |
| + int ret = 0; |
| + int len; |
| + const char *lease_ptr = ifname; |
| + const char *p = strchr(ifname, '='); |
| + |
| + if (interface_name_len) |
| + len = *interface_name_len; |
| + else |
| + len = strlen(ifname); |
| + |
| + if (p) { |
| + lease_ptr = p + 1; |
| + if (len > p - ifname) |
| + len = p - ifname; |
| + ret = 1; |
| + } |
| + |
| + if (interface_name_len) |
| + *interface_name_len = len; |
| + if (lease_identifier) |
| + *lease_identifier = lease_ptr; |
| + return ret; |
| +} |
| + |
| void |
| if_free(struct interface *ifp) |
| { |
| @@ -229,9 +257,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) |
| int i; |
| struct if_head *ifs; |
| struct interface *ifp; |
| -#ifdef __linux__ |
| + const char *lease_identifier; |
| char ifn[IF_NAMESIZE]; |
| + |
| +#ifdef __linux__ |
| + char alias[IF_NAMESIZE]; |
| #endif |
| + |
| #ifdef AF_LINK |
| const struct sockaddr_dl *sdl; |
| #ifdef SIOCGIFPRIORITY |
| @@ -287,28 +319,31 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) |
| if (ifp) |
| continue; |
| |
| + lease_identifier = NULL; |
| if (argc > 0) { |
| for (i = 0; i < argc; i++) { |
| + int intf_len = strlen(argv[i]); |
| + split_interface_lease(argv[i], &intf_len, |
| + &lease_identifier); |
| + if (intf_len > IF_NAMESIZE) |
| + continue; |
| + strlcpy(ifn, argv[i], intf_len + 1); |
| #ifdef __linux__ |
| + strlcpy(alias, argv[i], intf_len + 1); |
| /* Check the real interface name */ |
| - strlcpy(ifn, argv[i], sizeof(ifn)); |
| p = strchr(ifn, ':'); |
| if (p) |
| *p = '\0'; |
| +#endif |
| if (strcmp(ifn, ifa->ifa_name) == 0) |
| break; |
| -#else |
| - if (strcmp(argv[i], ifa->ifa_name) == 0) |
| - break; |
| -#endif |
| } |
| if (i == argc) |
| continue; |
| - p = argv[i]; |
| } else { |
| - p = ifa->ifa_name; |
| -#ifdef __linux__ |
| strlcpy(ifn, ifa->ifa_name, sizeof(ifn)); |
| +#ifdef __linux |
| + strlcpy(alias, ifa->ifa_name, sizeof(alias)); |
| #endif |
| /* -1 means we're discovering against a specific |
| * interface, but we still need the below rules |
| @@ -316,6 +351,8 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) |
| if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0) |
| continue; |
| } |
| + p = ifn; |
| + |
| for (i = 0; i < ctx->ifdc; i++) |
| if (!fnmatch(ctx->ifdv[i], p, 0)) |
| break; |
| @@ -351,11 +388,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) |
| } |
| ifp->ctx = ctx; |
| #ifdef __linux__ |
| - strlcpy(ifp->name, ifn, sizeof(ifp->name)); |
| - strlcpy(ifp->alias, p, sizeof(ifp->alias)); |
| -#else |
| - strlcpy(ifp->name, p, sizeof(ifp->name)); |
| + strlcpy(ifp->alias, alias, sizeof(ifp->alias)); |
| #endif |
| + strlcpy(ifp->name, p, sizeof(ifp->name)); |
| + if (lease_identifier) { |
| + strlcpy(ifp->lease_identifier, lease_identifier, |
| + sizeof(ifp->lease_identifier)); |
| + } |
| ifp->flags = ifa->ifa_flags; |
| ifp->carrier = if_carrier(ifp); |
| |
| diff --git a/if.h b/if.h |
| index cda4c01..a4c67a6 100644 |
| --- a/if.h |
| +++ b/if.h |
| @@ -105,6 +105,8 @@ int if_domtu(const char *, short int); |
| #define if_getmtu(iface) if_domtu(iface, 0) |
| #define if_setmtu(iface, mtu) if_domtu(iface, mtu) |
| int if_carrier(struct interface *); |
| +int split_interface_lease(const char *ifname, int *ifname_len, |
| + const char **lease_identifier); |
| |
| /* The below functions are provided by if-KERNEL.c */ |
| int if_conf(struct interface *); |
| -- |
| 2.2.0.rc0.207.ga3a616c |
| |