summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2018-03-10 11:50:08 +0000
committerRoy Marples <roy@marples.name>2018-03-10 11:50:08 +0000
commit3715c0a1b3fbb92dd08d07d5f6e8f3afa833ff0d (patch)
tree6ed8b5e1677de0eceec47f046f5eb148945cb4d0
parentc8d1a4150812b2d01c9cc2e5272a2ba19bc0196f (diff)
downloaddhcpcd-3715c0a1b3fbb92dd08d07d5f6e8f3afa833ff0d.tar.xz
dhcp6: deny unicast in non master mode
It seems that some DHCP6 servers or firewalls really insist on the client sending from the correct source port. This is the safest thing for the time being.
-rw-r--r--src/dhcp6.c61
1 files changed, 36 insertions, 25 deletions
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 7c35add9..08b9f283 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -777,6 +777,15 @@ dhcp6_makemessage(struct interface *ifp)
return -1;
}
+ /* In non master mode we listen and send from fixed addresses.
+ * We should try and match an address we have to unicast to,
+ * but for now this is the safest policy. */
+ if (unicast != NULL && !(ifp->ctx->options & DHCPCD_MASTER)) {
+ logdebugx("%s: ignoring unicast option as not master",
+ ifp->name);
+ unicast = NULL;
+ }
+
#ifdef AUTH
auth_len = 0;
if (ifo->auth.options & DHCPCD_AUTH_SEND) {
@@ -1092,6 +1101,8 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
uint8_t neg;
const char *broad_uni;
const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
+ struct ipv6_addr *lla;
+ int s;
if (!callback && ifp->carrier == LINK_DOWN)
return 0;
@@ -1104,12 +1115,13 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
#endif
state = D6_STATE(ifp);
+ lla = ipv6_linklocal(ifp);
/* We need to ensure we have sufficient scope to unicast the address */
/* XXX FIXME: We should check any added addresses we have like from
* a Router Advertisement */
if (IN6_IS_ADDR_UNSPECIFIED(&state->unicast) ||
(state->state == DH6S_REQUEST &&
- (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || !ipv6_linklocal(ifp))))
+ (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || lla == NULL)))
{
dst.sin6_addr = alldhcp;
broad_uni = "broadcasting";
@@ -1251,7 +1263,16 @@ logsend:
ctx->sndhdr.msg_controllen = 0;
}
- if (sendmsg(ctx->dhcp6_fd, &ctx->sndhdr, 0) == -1) {
+ if (ctx->dhcp6_fd != -1)
+ s = ctx->dhcp6_fd;
+ else if (lla != NULL && lla->dhcp6_fd != -1)
+ s = lla->dhcp6_fd;
+ else {
+ logerrx("%s: no socket to send from", ifp->name);
+ return -1;
+ }
+
+ if (sendmsg(s, &ctx->sndhdr, 0) == -1) {
logerr("%s: %s: sendmsg", __func__, ifp->name);
/* Allow DHCPv6 to continue .... the errors
* would be rate limited by the protocol.
@@ -3551,19 +3572,16 @@ dhcp6_listen(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
if (ia != NULL) {
memcpy(&sa.sin6_addr, &ia->addr, sizeof(sa.sin6_addr));
sa.sin6_scope_id = ia->iface->index;
- } else if (!(ctx->options & DHCPCD_MASTER))
- /* This socket is only used for sending. */
- return s;
+ }
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1)
goto errexit;
- if (ia == NULL) {
- n = 1;
- if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
- &n, sizeof(n)) == -1)
- goto errexit;
- } else {
+ n = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &n, sizeof(n)) == -1)
+ goto errexit;
+
+ if (ia != NULL) {
ia->dhcp6_fd = s;
eloop_event_add(ctx->eloop, s, dhcp6_recvaddr, ia);
}
@@ -3577,18 +3595,6 @@ errexit:
return -1;
}
-static int
-dhcp6_open(struct dhcpcd_ctx *ctx)
-{
-
- /* Open an unbound socket to send from. */
- ctx->dhcp6_fd = dhcp6_listen(ctx, NULL);
- if (ctx->dhcp6_fd != -1 && (ctx->options & DHCPCD_MASTER))
- eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
-
- return ctx->dhcp6_fd;
-}
-
#ifndef SMALL
static void
dhcp6_activateinterfaces(struct interface *ifp)
@@ -3623,13 +3629,18 @@ static void
dhcp6_start1(void *arg)
{
struct interface *ifp = arg;
+ struct dhcpcd_ctx *ctx = ifp->ctx;
struct if_options *ifo = ifp->options;
struct dhcp6_state *state;
size_t i;
const struct dhcp_compat *dhc;
- if (ifp->ctx->dhcp6_fd == -1 && dhcp6_open(ifp->ctx) == -1)
- return;
+ if (ctx->dhcp6_fd == -1 && ctx->options & DHCPCD_MASTER) {
+ ctx->dhcp6_fd = dhcp6_listen(ctx, NULL);
+ if (ctx->dhcp6_fd == -1)
+ return;
+ eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
+ }
state = D6_STATE(ifp);
/* If no DHCPv6 options are configured,