mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e25db1f273 | ||
|
|
79cb46c0e9 | ||
|
|
22ce550e53 | ||
|
|
30393100c1 | ||
|
|
459380965a | ||
|
|
21bac1bccd | ||
|
|
b1a1b6def5 | ||
|
|
baeb3adf21 | ||
|
|
39f6a04ca4 | ||
|
|
37c9ccebd1 | ||
|
|
71c73ac17c |
No files matched your search
@@ -14,6 +14,18 @@ version 2.66
|
|||||||
dnsmasq configuration file or restart the daemon. Thanks to
|
dnsmasq configuration file or restart the daemon. Thanks to
|
||||||
Steven Barth for extensive testing and development work on
|
Steven Barth for extensive testing and development work on
|
||||||
this idea.
|
this idea.
|
||||||
|
|
||||||
|
Fix crash on startup on Solaris 11. Regression probably
|
||||||
|
introduced in 2.61. Thanks to Geoff Johnstone for the
|
||||||
|
patch.
|
||||||
|
|
||||||
|
Add code to make behaviour for TCP DNS requests that same
|
||||||
|
as for UDP requests, when a request arrives for an allowed
|
||||||
|
address, but via a banned interface. This change is only
|
||||||
|
active on Linux, since the relevant API is missing (AFAIK)
|
||||||
|
on other platforms. Many thanks to Tomas Hozza for
|
||||||
|
spotting the problem, and doing invaluable discovery of
|
||||||
|
the obscure and undocumented API required for the solution.
|
||||||
|
|
||||||
|
|
||||||
version 2.65
|
version 2.65
|
||||||
|
|||||||
+9
-3
@@ -717,7 +717,13 @@ A single
|
|||||||
.B dhcp-host
|
.B dhcp-host
|
||||||
may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
|
may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
|
||||||
.B --dhcp-host=laptop,[1234::56]
|
.B --dhcp-host=laptop,[1234::56]
|
||||||
Note that in IPv6 DHCP, the hardware address is not normally available, so a client must be identified by client-id (called client DUID in IPv6-land) or hostname.
|
IPv6 addresses may contain only the host-identifier part:
|
||||||
|
.B --dhcp-host=laptop,[::56]
|
||||||
|
in which case thay act as wildcards in constructed dhcp ranges, with
|
||||||
|
the appropriate network part inserted.
|
||||||
|
Note that in IPv6 DHCP, the hardware address is not normally
|
||||||
|
available, so a client must be identified by client-id (called client
|
||||||
|
DUID in IPv6-land) or hostname.
|
||||||
|
|
||||||
The special option id:* means "ignore any client-id
|
The special option id:* means "ignore any client-id
|
||||||
and use MAC addresses only." This is useful when a client presents a client-id sometimes
|
and use MAC addresses only." This is useful when a client presents a client-id sometimes
|
||||||
@@ -1709,7 +1715,7 @@ The simplest configuration consists of two lines of dnsmasq configuration; somet
|
|||||||
|
|
||||||
.nf
|
.nf
|
||||||
.B auth-server=server.example.com,eth0
|
.B auth-server=server.example.com,eth0
|
||||||
.B auth=zone=our.zone.com,1.2.3.0/24
|
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
and two records in the external DNS
|
and two records in the external DNS
|
||||||
@@ -1733,7 +1739,7 @@ we have
|
|||||||
|
|
||||||
.nf
|
.nf
|
||||||
.B auth-server=our.zone.com,eth0
|
.B auth-server=our.zone.com,eth0
|
||||||
.B auth=zone=our.zone.com,1.2.3.0/24
|
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
.nf
|
.nf
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
{
|
{
|
||||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||||
|
|
||||||
if (iface_index == 0)
|
if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (family == AF_INET)
|
if (family == AF_INET)
|
||||||
@@ -119,7 +119,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
struct in_addr addr, netmask, broadcast;
|
struct in_addr addr, netmask, broadcast;
|
||||||
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
||||||
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
if (addrs->ifa_broadaddr)
|
||||||
|
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||||
|
else
|
||||||
|
broadcast.s_addr = 0;
|
||||||
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-44
@@ -679,7 +679,7 @@ void log_context(int family, struct dhcp_context *context)
|
|||||||
|
|
||||||
void *start = &context->start;
|
void *start = &context->start;
|
||||||
void *end = &context->end;
|
void *end = &context->end;
|
||||||
char *n = "", *m = "", *p = daemon->namebuff;
|
char *template = "", *p = daemon->namebuff;
|
||||||
|
|
||||||
*p = 0;
|
*p = 0;
|
||||||
|
|
||||||
@@ -694,67 +694,59 @@ void log_context(int family, struct dhcp_context *context)
|
|||||||
end = &context->end6;
|
end = &context->end6;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((context->flags & CONTEXT_DHCP) ||
|
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
|
||||||
!(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)))
|
strcpy(daemon->namebuff, _(", prefix deprecated"));
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
|
p += sprintf(p, _(", lease time "));
|
||||||
strcpy(daemon->namebuff, _(", prefix deprecated"));
|
prettyprint_time(p, context->lease_time);
|
||||||
else
|
p += strlen(p);
|
||||||
{
|
}
|
||||||
p += sprintf(p, _(", lease time "));
|
|
||||||
m = p;
|
|
||||||
prettyprint_time(p, context->lease_time);
|
|
||||||
p += strlen(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||||
{
|
{
|
||||||
char ifrn_name[IFNAMSIZ];
|
char ifrn_name[IFNAMSIZ];
|
||||||
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
|
|
||||||
{
|
template = p;
|
||||||
n = p;
|
p += sprintf(p, ", ");
|
||||||
p += sprintf(p, ", constructed for %s", ifrn_name);
|
|
||||||
}
|
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
|
||||||
}
|
sprintf(p, "constructed for %s", ifrn_name);
|
||||||
|
}
|
||||||
if (context->flags & CONTEXT_TEMPLATE)
|
else if (context->flags & CONTEXT_TEMPLATE)
|
||||||
{
|
{
|
||||||
n = p;
|
template = p;
|
||||||
p += sprintf(p, ", template for %s%s", context->template_interface,
|
p += sprintf(p, ", ");
|
||||||
(context->flags & CONTEXT_WILDCARD) ? "*" : "");
|
|
||||||
}
|
sprintf(p, "template for %s%s", context->template_interface,
|
||||||
|
(context->flags & CONTEXT_WILDCARD) ? "*" : "");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
|
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||||
{
|
{
|
||||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||||
my_syslog(MS_DHCP | LOG_INFO,
|
my_syslog(MS_DHCP | LOG_INFO,
|
||||||
(context->flags & CONTEXT_RA_STATELESS) ?
|
(context->flags & CONTEXT_RA_STATELESS) ?
|
||||||
_("%s stateless on %s%.0s%.0s") :
|
_("%s stateless on %s%.0s%.0s%s") :
|
||||||
(context->flags & CONTEXT_STATIC) ?
|
(context->flags & CONTEXT_STATIC) ?
|
||||||
_("%s, static leases only on %.0s%s%s") :
|
_("%s, static leases only on %.0s%s%s%.0s") :
|
||||||
(context->flags & CONTEXT_PROXY) ?
|
(context->flags & CONTEXT_PROXY) ?
|
||||||
_("%s, proxy on subnet %.0s%s%.0s") :
|
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
|
||||||
_("%s, IP range %s -- %s%s"),
|
_("%s, IP range %s -- %s%s%.0s"),
|
||||||
(family != AF_INET) ? "DHCPv6" : "DHCP",
|
(family != AF_INET) ? "DHCPv6" : "DHCP",
|
||||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
|
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
if (context->flags & CONTEXT_RA_NAME)
|
if (context->flags & CONTEXT_RA_NAME)
|
||||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"),
|
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
|
||||||
daemon->addrbuff, n);
|
|
||||||
|
|
||||||
|
|
||||||
if (context->flags & CONTEXT_RA)
|
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
|
||||||
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s%s"),
|
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
|
||||||
daemon->addrbuff,
|
|
||||||
(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)) ? "" : ", prefix valid ",
|
|
||||||
(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)) ? n : m);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-19
@@ -211,7 +211,8 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
|||||||
|
|
||||||
for (context = daemon->dhcp6; context; context = context->next)
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
{
|
{
|
||||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
if ((context->flags & CONTEXT_DHCP) &&
|
||||||
|
!(context->flags & CONTEXT_TEMPLATE) &&
|
||||||
prefix == context->prefix &&
|
prefix == context->prefix &&
|
||||||
is_same_net6(local, &context->start6, prefix) &&
|
is_same_net6(local, &context->start6, prefix) &&
|
||||||
is_same_net6(local, &context->end6, prefix))
|
is_same_net6(local, &context->end6, prefix))
|
||||||
@@ -328,6 +329,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* can dynamically allocate addr */
|
||||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||||
struct in6_addr *taddr,
|
struct in6_addr *taddr,
|
||||||
struct dhcp_netid *netids)
|
struct dhcp_netid *netids)
|
||||||
@@ -352,6 +354,21 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* address OK if configured */
|
||||||
|
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||||
|
struct in6_addr *taddr,
|
||||||
|
struct dhcp_netid *netids)
|
||||||
|
{
|
||||||
|
struct dhcp_context *tmp;
|
||||||
|
|
||||||
|
for (tmp = context; tmp; tmp = tmp->current)
|
||||||
|
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||||
|
match_netid(tmp->filter, netids, 1))
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||||
struct in6_addr *taddr,
|
struct in6_addr *taddr,
|
||||||
struct dhcp_netid *netids)
|
struct dhcp_netid *netids)
|
||||||
@@ -366,21 +383,12 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
|||||||
|
|
||||||
struct dhcp_context *tmp;
|
struct dhcp_context *tmp;
|
||||||
|
|
||||||
if (!(tmp = address6_available(context, taddr, netids)))
|
if (!(tmp = address6_available(context, taddr, netids)) &&
|
||||||
{
|
!(tmp = address6_valid(context, taddr, netids)))
|
||||||
for (tmp = context; tmp; tmp = tmp->current)
|
for (tmp = context; tmp; tmp = tmp->current)
|
||||||
if (match_netid(tmp->filter, netids, 1) &&
|
if (match_netid(tmp->filter, netids, 1) &&
|
||||||
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
|
is_same_net6(taddr, &tmp->start6, tmp->prefix))
|
||||||
(tmp->flags & CONTEXT_STATIC))
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
if (!tmp)
|
|
||||||
for (tmp = context; tmp; tmp = tmp->current)
|
|
||||||
if (match_netid(tmp->filter, netids, 1) &&
|
|
||||||
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
|
|
||||||
!(tmp->flags & CONTEXT_PROXY))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only one context allowed now */
|
/* Only one context allowed now */
|
||||||
if (tmp)
|
if (tmp)
|
||||||
@@ -391,11 +399,19 @@ struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
|||||||
|
|
||||||
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||||
{
|
{
|
||||||
if (!context) /* called via find_config() from lease_update_from_configs() */
|
/* expand wildcard on contructed contexts */
|
||||||
return 1;
|
if ((config->flags & CONFIG_WILDCARD) &&
|
||||||
|
(context->flags & CONTEXT_CONSTRUCTED))
|
||||||
|
{
|
||||||
|
u64 addrpart = addr6part(&config->addr6);
|
||||||
|
config->addr6 = context->start6;
|
||||||
|
setaddr6part(&config->addr6, addrpart);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
|
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-19
@@ -1337,7 +1337,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
|
|
||||||
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
|
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
|
||||||
{
|
{
|
||||||
int confd;
|
int confd, client_ok = 1;
|
||||||
struct irec *iface = NULL;
|
struct irec *iface = NULL;
|
||||||
pid_t p;
|
pid_t p;
|
||||||
union mysockaddr tcp_addr;
|
union mysockaddr tcp_addr;
|
||||||
@@ -1348,25 +1348,58 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
if (confd == -1 ||
|
if (confd == -1 ||
|
||||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
if (option_bool(OPT_NOWILD))
|
||||||
iface = listener->iface; /* May be NULL */
|
iface = listener->iface; /* May be NULL */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Check for allowed interfaces when binding the wildcard address:
|
int if_index;
|
||||||
we do this by looking for an interface with the same address as
|
char intr_name[IF_NAMESIZE];
|
||||||
the local address of the TCP connection, then looking to see if that's
|
|
||||||
an allowed interface. As a side effect, we get the netmask of the
|
/* In full wildcard mode, need to refresh interface list.
|
||||||
interface too, for localisation. */
|
This happens automagically in CLEVERBIND */
|
||||||
|
if (!option_bool(OPT_CLEVERBIND))
|
||||||
/* interface may be new since startup */
|
enumerate_interfaces();
|
||||||
if (enumerate_interfaces())
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
/* if we can find the arrival interface, check it's one that's allowed */
|
||||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||||
break;
|
indextoname(listener->tcpfd, if_index, intr_name))
|
||||||
}
|
{
|
||||||
|
struct all_addr addr;
|
||||||
if (!iface && !(option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)))
|
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||||
|
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->index == if_index)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||||
|
client_ok = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option_bool(OPT_CLEVERBIND))
|
||||||
|
iface = listener->iface; /* May be NULL */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check for allowed interfaces when binding the wildcard address:
|
||||||
|
we do this by looking for an interface with the same address as
|
||||||
|
the local address of the TCP connection, then looking to see if that's
|
||||||
|
an allowed interface. As a side effect, we get the netmask of the
|
||||||
|
interface too, for localisation. */
|
||||||
|
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!iface)
|
||||||
|
client_ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client_ok)
|
||||||
{
|
{
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
|
|||||||
@@ -593,6 +593,7 @@ struct dhcp_config {
|
|||||||
#define CONFIG_DECLINED 1024 /* address declined by client */
|
#define CONFIG_DECLINED 1024 /* address declined by client */
|
||||||
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
||||||
#define CONFIG_ADDR6 4096
|
#define CONFIG_ADDR6 4096
|
||||||
|
#define CONFIG_WILDCARD 8192
|
||||||
|
|
||||||
struct dhcp_opt {
|
struct dhcp_opt {
|
||||||
int opt, len, flags;
|
int opt, len, flags;
|
||||||
@@ -1001,7 +1002,9 @@ void create_wildcard_listeners(void);
|
|||||||
void create_bound_listeners(int die);
|
void create_bound_listeners(int die);
|
||||||
int is_dad_listeners(void);
|
int is_dad_listeners(void);
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
||||||
|
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
|
||||||
int fix_fd(int fd);
|
int fix_fd(int fd);
|
||||||
|
int tcp_interface(int fd, int af);
|
||||||
struct in_addr get_ifaddr(char *intr);
|
struct in_addr get_ifaddr(char *intr);
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
int set_ipv6pktinfo(int fd);
|
int set_ipv6pktinfo(int fd);
|
||||||
@@ -1149,6 +1152,9 @@ int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr);
|
|||||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||||
struct in6_addr *taddr,
|
struct in6_addr *taddr,
|
||||||
struct dhcp_netid *netids);
|
struct dhcp_netid *netids);
|
||||||
|
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||||
|
struct in6_addr *taddr,
|
||||||
|
struct dhcp_netid *netids);
|
||||||
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||||
struct in6_addr *taddr,
|
struct in6_addr *taddr,
|
||||||
struct dhcp_netid *netids);
|
struct dhcp_netid *netids);
|
||||||
|
|||||||
+10
-3
@@ -763,10 +763,17 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
/* enforce available interface configuration */
|
/* enforce available interface configuration */
|
||||||
|
|
||||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
if (!indextoname(listen->fd, if_index, ifr.ifr_name))
|
||||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||||
|
{
|
||||||
|
if (!option_bool(OPT_CLEVERBIND))
|
||||||
|
enumerate_interfaces();
|
||||||
|
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||||
{
|
{
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
@@ -780,7 +787,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* interface may be new */
|
/* interface may be new */
|
||||||
if (!iface)
|
if (!iface && !option_bool(OPT_CLEVERBIND))
|
||||||
enumerate_interfaces();
|
enumerate_interfaces();
|
||||||
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
|||||||
+105
-1
@@ -170,7 +170,40 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fix for problem that the kernel sometimes reports the loopback inerface as the
|
||||||
|
arrival interface when a packet originates locally, even when sent to address of
|
||||||
|
an interface other than the loopback. Accept packet if it arrived via a loopback
|
||||||
|
interface, even when we're not accepting packets that way, as long as the destination
|
||||||
|
address is one we're believing. Interface list must be up-to-date before calling. */
|
||||||
|
int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
|
||||||
|
{
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct irec *iface;
|
||||||
|
|
||||||
|
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||||
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
|
||||||
|
ifr.ifr_flags & IFF_LOOPBACK)
|
||||||
|
{
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->addr.sa.sa_family == family)
|
||||||
|
{
|
||||||
|
if (family == AF_INET)
|
||||||
|
{
|
||||||
|
if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6))
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int iface_allowed(struct irec **irecp, int if_index,
|
static int iface_allowed(struct irec **irecp, int if_index,
|
||||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||||
{
|
{
|
||||||
@@ -459,6 +492,77 @@ int set_ipv6pktinfo(int fd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
|
||||||
|
int tcp_interface(int fd, int af)
|
||||||
|
{
|
||||||
|
int if_index = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
|
int opt = 1;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
struct msghdr msg;
|
||||||
|
|
||||||
|
/* use mshdr do that the CMSDG_* macros are available */
|
||||||
|
msg.msg_control = daemon->packet;
|
||||||
|
msg.msg_controllen = daemon->packet_buff_sz;
|
||||||
|
|
||||||
|
/* we overwrote the buffer... */
|
||||||
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
|
if (af == AF_INET)
|
||||||
|
{
|
||||||
|
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
|
||||||
|
getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned char *c;
|
||||||
|
struct in_pktinfo *p;
|
||||||
|
} p;
|
||||||
|
|
||||||
|
p.c = CMSG_DATA(cmptr);
|
||||||
|
if_index = p.p->ipi_ifindex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Only the RFC-2292 API has the ability to find the interface for TCP connections,
|
||||||
|
it was removed in RFC-3542 !!!!
|
||||||
|
|
||||||
|
Fortunately, Linux kept the 2292 ABI when it moved to 3542. The following code always
|
||||||
|
uses the old ABI, and should work with pre- and post-3542 kernel headers */
|
||||||
|
|
||||||
|
#ifdef IPV6_2292PKTOPTIONS
|
||||||
|
# define PKTOPTIONS IPV6_2292PKTOPTIONS
|
||||||
|
#else
|
||||||
|
# define PKTOPTIONS IPV6_PKTOPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (set_ipv6pktinfo(fd) &&
|
||||||
|
getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
|
||||||
|
{
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned char *c;
|
||||||
|
struct in6_pktinfo *p;
|
||||||
|
} p;
|
||||||
|
p.c = CMSG_DATA(cmptr);
|
||||||
|
|
||||||
|
if_index = p.p->ipi6_ifindex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* IPV6 */
|
||||||
|
#endif /* Linux */
|
||||||
|
|
||||||
|
return if_index;
|
||||||
|
}
|
||||||
|
|
||||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2468,6 +2468,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
|
|
||||||
if (!inet_pton(AF_INET6, arg, &new->addr6))
|
if (!inet_pton(AF_INET6, arg, &new->addr6))
|
||||||
ret_err(_("bad IPv6 address"));
|
ret_err(_("bad IPv6 address"));
|
||||||
|
|
||||||
|
for (i= 0; i < 8; i++)
|
||||||
|
if (new->addr6.s6_addr[i] != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* set WILDCARD if network part all zeros */
|
||||||
|
if (i == 8)
|
||||||
|
new->flags |= CONFIG_WILDCARD;
|
||||||
|
|
||||||
new->flags |= CONFIG_ADDR6;
|
new->flags |= CONFIG_ADDR6;
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-31
@@ -82,18 +82,20 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
|
|||||||
{
|
{
|
||||||
struct dhcp_context *c;
|
struct dhcp_context *c;
|
||||||
context = NULL;
|
context = NULL;
|
||||||
|
|
||||||
|
if (!IN6_IS_ADDR_LOOPBACK(link_address) &&
|
||||||
|
!IN6_IS_ADDR_LINKLOCAL(link_address) &&
|
||||||
|
!IN6_IS_ADDR_MULTICAST(link_address))
|
||||||
|
for (c = daemon->dhcp6; c; c = c->next)
|
||||||
|
if ((c->flags & CONTEXT_DHCP) &&
|
||||||
|
!(c->flags & CONTEXT_TEMPLATE) &&
|
||||||
|
is_same_net6(link_address, &c->start6, c->prefix) &&
|
||||||
|
is_same_net6(link_address, &c->end6, c->prefix))
|
||||||
|
{
|
||||||
|
c->current = context;
|
||||||
|
context = c;
|
||||||
|
}
|
||||||
|
|
||||||
for (c = daemon->dhcp6; c; c = c->next)
|
|
||||||
if (!IN6_IS_ADDR_LOOPBACK(link_address) &&
|
|
||||||
!IN6_IS_ADDR_LINKLOCAL(link_address) &&
|
|
||||||
!IN6_IS_ADDR_MULTICAST(link_address) &&
|
|
||||||
is_same_net6(link_address, &c->start6, c->prefix) &&
|
|
||||||
is_same_net6(link_address, &c->end6, c->prefix))
|
|
||||||
{
|
|
||||||
c->current = context;
|
|
||||||
context = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
{
|
{
|
||||||
inet_ntop(AF_INET6, link_address, daemon->addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET6, link_address, daemon->addrbuff, ADDRSTRLEN);
|
||||||
@@ -525,32 +527,38 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
|||||||
{
|
{
|
||||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||||
requested_time = opt6_uint(ia_option, 16, 4);
|
requested_time = opt6_uint(ia_option, 16, 4);
|
||||||
|
struct dhcp_context *dynamic;
|
||||||
if (!address6_available(context, req_addr, tags) &&
|
|
||||||
(!have_config(config, CONFIG_ADDR6) || memcmp(&config->addr6, req_addr, IN6ADDRSZ) != 0))
|
if ((dynamic = address6_available(context, req_addr, tags)) || address6_valid(context, req_addr, tags))
|
||||||
{
|
{
|
||||||
if (msg_type == DHCP6REQUEST)
|
if (!dynamic && !(have_config(config, CONFIG_ADDR6) && memcmp(&config->addr6, req_addr, IN6ADDRSZ) == 0))
|
||||||
{
|
{
|
||||||
/* host has a lease, but it's not on the correct link */
|
/* Static range, not configured. */
|
||||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||||
put_opt6_short(DHCP6NOTONLINK);
|
put_opt6_short(DHCP6UNSPEC);
|
||||||
put_opt6_string("Not on link");
|
put_opt6_string("Address unavailable");
|
||||||
end_opt6(o1);
|
end_opt6(o1);
|
||||||
}
|
}
|
||||||
|
else if (lease6_find_by_addr(req_addr, 128, 0) &&
|
||||||
|
!(lease = lease6_find(clid, clid_len, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, req_addr)))
|
||||||
|
{
|
||||||
|
/* Address leased to another DUID/IAID */
|
||||||
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||||
|
put_opt6_short(DHCP6UNSPEC);
|
||||||
|
put_opt6_string("Address in use");
|
||||||
|
end_opt6(o1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addrp = req_addr;
|
||||||
}
|
}
|
||||||
else if ((lease = lease6_find(NULL, 0, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
else if (msg_type == DHCP6REQUEST)
|
||||||
iaid, req_addr)) &&
|
|
||||||
(clid_len != lease->clid_len ||
|
|
||||||
memcmp(clid, lease->clid, clid_len) != 0))
|
|
||||||
{
|
{
|
||||||
/* Address leased to another DUID */
|
/* requested address not on the correct link */
|
||||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||||
put_opt6_short(DHCP6UNSPEC);
|
put_opt6_short(DHCP6NOTONLINK);
|
||||||
put_opt6_string("Address in use");
|
put_opt6_string("Not on link");
|
||||||
end_opt6(o1);
|
end_opt6(o1);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
addrp = req_addr;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -567,9 +575,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
|||||||
inet_ntop(AF_INET6, &config->addr6, daemon->addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &config->addr6, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
if (ltmp && ltmp->clid &&
|
if (ltmp && ltmp->clid &&
|
||||||
(ltmp->clid_len != clid_len || memcmp(ltmp->clid, clid, clid_len) != 0))
|
(ltmp->clid_len != clid_len || memcmp(ltmp->clid, clid, clid_len) != 0 || ltmp->hwaddr_type != iaid))
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
|
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s#%d"),
|
||||||
daemon->addrbuff, print_mac(daemon->namebuff, ltmp->clid, ltmp->clid_len));
|
daemon->addrbuff, print_mac(daemon->namebuff, ltmp->clid, ltmp->clid_len), ltmp->hwaddr_type);
|
||||||
else if (have_config(config, CONFIG_DECLINED) &&
|
else if (have_config(config, CONFIG_DECLINED) &&
|
||||||
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
|
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"),
|
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"),
|
||||||
|
|||||||
+11
-6
@@ -61,6 +61,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
char *prefix = daemon->tftp_prefix;
|
char *prefix = daemon->tftp_prefix;
|
||||||
struct tftp_prefix *pref;
|
struct tftp_prefix *pref;
|
||||||
|
struct all_addr addra;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct cmsghdr align; /* this ensures alignment */
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
@@ -189,18 +190,22 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
name = namebuff;
|
name = namebuff;
|
||||||
|
|
||||||
|
addra.addr.addr4 = addr.in.sin_addr;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
|
addra.addr.addr6 = addr.in6.sin6_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!iface_check(listen->family, &addra, name, NULL))
|
||||||
{
|
{
|
||||||
if (!iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, NULL))
|
if (!option_bool(OPT_CLEVERBIND))
|
||||||
|
enumerate_interfaces();
|
||||||
|
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (!iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, NULL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
/* allowed interfaces are the same as for DHCP */
|
/* allowed interfaces are the same as for DHCP */
|
||||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
|
|||||||
Reference in new issue
Block a user