Compare commits
16 Commits
v2.92test2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8f66f4fda | ||
|
|
629107bd6d | ||
|
|
05464a173b | ||
|
|
ae3d3d971e | ||
|
|
d1845782d6 | ||
|
|
edb5f85fd1 | ||
|
|
cef74423e2 | ||
|
|
959dead673 | ||
|
|
eb60168382 | ||
|
|
57a2f5778c | ||
|
|
7d5fbe7da3 | ||
|
|
ded935be37 | ||
|
|
aa9b71c681 | ||
|
|
e497f3f2c8 | ||
|
|
ee09f0655c | ||
|
|
052aa0fcf3 |
10
CHANGELOG
10
CHANGELOG
@@ -24,7 +24,7 @@ version 2.92
|
||||
|
||||
Fix some edge-cases with domains and --address and --server. There
|
||||
has been some regressions with this in previous releases. This change
|
||||
fixes the priority order from loqwer to highest as:
|
||||
fixes the priority order from lower to highest as:
|
||||
--address with a IPv4 or IPv6 address (as long as the query matches the type)
|
||||
--address with # for all-zeros, as long as the query is A or AAAA)
|
||||
--address with no address, which returns NXDOMAIN or NOERROR for all types.
|
||||
@@ -61,7 +61,7 @@ version 2.92
|
||||
|
||||
Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349).
|
||||
|
||||
Change the behaviour of the DHVPv6 server when a REBIND message
|
||||
Change the behaviour of the DHCPv6 server when a REBIND message
|
||||
is received but no lease exists. Under these circumstances a new
|
||||
lease is created _only_ when the --dhcp-authoritative option is
|
||||
set. This matches the behavior of the DHCPv4 server.
|
||||
@@ -70,6 +70,12 @@ version 2.92
|
||||
is functional when client and server networks aren't mutually
|
||||
route-able.
|
||||
|
||||
Fix failure to add client MAC address to queries in TCP mode.
|
||||
The options which cause dnsmasq to decorate a DNS query with the MAC
|
||||
address on the originating client can fail when the query is sent
|
||||
using TCP. Thanks to Bruno Ravara for spotting and
|
||||
characterising this bug.
|
||||
|
||||
|
||||
version 2.91
|
||||
Fix spurious "resource limit exceeded messages". Thanks to
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
@@ -193,11 +193,11 @@
|
||||
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
#dhcp-range=1234::, ra-only
|
||||
#dhcp-range=1234::, ra-only
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# MAC address and assume that the host will also have an
|
||||
# IPv6 address calculated using the SLAAC algorithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
@@ -220,9 +220,9 @@
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
#enable-ra
|
||||
|
||||
@@ -295,11 +295,11 @@
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also that the [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
@@ -355,7 +355,7 @@
|
||||
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
@@ -560,7 +560,7 @@
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
@@ -918,7 +918,7 @@ fast.
|
||||
|
||||
Versions of dnsmasq prior to 2.80 defaulted to not checking unsigned replies, and used
|
||||
.B --dnssec-check-unsigned
|
||||
to switch this on. Such configurations will continue to work as before, but those which used the default of no checking will need to be altered to explicitly select no checking. The new default is because switching off checking for unsigned replies is inherently dangerous. Not only does it open the possiblity of forged replies, but it allows everything to appear to be working even when the upstream namesevers do not support DNSSEC, and in this case no DNSSEC validation at all is occurring.
|
||||
to switch this on. Such configurations will continue to work as before, but those which used the default of no checking will need to be altered to explicitly select no checking. The new default is because switching off checking for unsigned replies is inherently dangerous. Not only does it open the possibility of forged replies, but it allows everything to appear to be working even when the upstream namesevers do not support DNSSEC, and in this case no DNSSEC validation at all is occurring.
|
||||
.TP
|
||||
.B --dnssec-no-timecheck
|
||||
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
|
||||
@@ -1197,7 +1197,7 @@ the appropriate network part inserted. For IPv6, an address may include a prefix
|
||||
which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability
|
||||
to specify multiple addresses) is useful
|
||||
when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows
|
||||
dnsmasq to honour the static address allocation but assign a different adddress for each DUID. This
|
||||
dnsmasq to honour the static address allocation but assign a different address for each DUID. This
|
||||
typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address.
|
||||
|
||||
Note that in IPv6 DHCP, the hardware address may not be
|
||||
@@ -1347,7 +1347,7 @@ The special address 0.0.0.0 means "the address of the system running dnsmasq".
|
||||
|
||||
An option without data is valid, and includes just the option without data.
|
||||
(There is only one option with a zero length data field currently defined for DHCPv4, 80:rapid commit, so this feature is not very useful in practice). Options for which dnsmasq normally
|
||||
provides default values can be ommitted by defining the option with no data. These are
|
||||
provides default values can be omitted by defining the option with no data. These are
|
||||
netmask, broadcast, router, DNS server, domainname and hostname. Thus, for DHCPv4
|
||||
.B --dhcp-option = option:router
|
||||
will result in no router option being sent, rather than the default of the host on which dnsmasq is running. For DHCPv6, the same is true of the options DNS server and refresh time.
|
||||
@@ -1490,7 +1490,7 @@ prefix-delegation from relayed DHCP transactions. See
|
||||
for details.
|
||||
.TP
|
||||
.B --dhcp-split-relay=<local address>,[<server address>[#<server port>]],<server-facing-interface>|<server-facing-address>
|
||||
A usefully enchanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
||||
A usefully enhanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
||||
for two functions; it is used by the DHCP server to determine which network to allocate
|
||||
an address on, and it is used as the address of the relay to which the server sends packets.
|
||||
|
||||
@@ -1501,7 +1501,7 @@ local address is also used as server-ID override so that the client always sends
|
||||
via the relay. The effect of this is that server doesn't require
|
||||
a route to the client network and the clients don't require a route to the server.
|
||||
|
||||
The third parameter is mandatory. If it is an interface name it cannot be a wildcard and the same filtering as descibed in
|
||||
The third parameter is mandatory. If it is an interface name it cannot be a wildcard and the same filtering as described in
|
||||
--dhcp-relay applies; answers from the server must arrve via the specified interface. If the third parameter
|
||||
is an IP address it must be an address of a local interface which is routable from the server; In this case no filtering
|
||||
is done, the reply packets can arrive via any route.
|
||||
@@ -1672,7 +1672,7 @@ likely to move IP address; for this reason it should not be generally used.
|
||||
.TP
|
||||
.B --dhcp-ignore-clid
|
||||
Dnsmasq is reading 'client identifier' (RFC 2131) option sent by clients
|
||||
(if available) to identify clients. This allow to serve same IP address
|
||||
(if available) to identify clients. This allow one to serve same IP address
|
||||
for a host using several interfaces. Use this option to disable 'client identifier'
|
||||
reading, i.e. to always identify a host using the MAC address.
|
||||
.TP
|
||||
@@ -1953,7 +1953,7 @@ was sent, and the complete pathname of the file.
|
||||
|
||||
The "relay-snoop" action is invoked when dnsmasq is configured as a DHCP
|
||||
relay for DHCPv6 and it relays a prefx delegation to a client. The arguments
|
||||
are the name of the interface where the client is conected, its (link-local)
|
||||
are the name of the interface where the client is connected, its (link-local)
|
||||
address on that interface and the delegated prefix. This information is
|
||||
sufficient to install routes to the delegated prefix of a router. See
|
||||
.B --dhcp-relay
|
||||
@@ -2304,7 +2304,7 @@ therein is updated when dnsmasq receives SIGHUP.
|
||||
.B \--conf-script=<file>[ <arg]
|
||||
Execute <file>, and treat what it emits to stdout as the contents of a configuration file.
|
||||
If the script exits with a non-zero exit code, dnsmasq treats this as a fatal error.
|
||||
The script can be passed arguments, space seperated from the filename and each other so, for instance
|
||||
The script can be passed arguments, space separated from the filename and each other so, for instance
|
||||
.B --conf-dir="/etc/dnsmasq-uncompress-ads /share/ads-domains.gz"
|
||||
|
||||
with /etc/dnsmasq-uncompress-ads containing
|
||||
|
||||
2870
man/sv/dnsmasq.8
Normal file
2870
man/sv/dnsmasq.8
Normal file
File diff suppressed because it is too large
Load Diff
1589
po/pt_BR.po
1589
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
18
src/arp.c
18
src/arp.c
@@ -111,22 +111,26 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
|
||||
|
||||
again:
|
||||
|
||||
/* If the database is less then INTERVAL old, look in there */
|
||||
if (difftime(now, last) < INTERVAL)
|
||||
/* If the database is less then INTERVAL old, look in there.
|
||||
|
||||
If we're a child process, we always rely on the existing cache we
|
||||
inherited from the parent, since we don't have a netlink socket.
|
||||
*/
|
||||
if (difftime(now, last) < INTERVAL || daemon->pipe_to_parent != -1)
|
||||
{
|
||||
/* addr == NULL -> just make cache up-to-date */
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
{
|
||||
if (addr->sa.sa_family != arp->family)
|
||||
continue;
|
||||
|
||||
|
||||
if (arp->family == AF_INET &&
|
||||
arp->addr.addr4.s_addr != addr->in.sin_addr.s_addr)
|
||||
continue;
|
||||
|
||||
|
||||
if (arp->family == AF_INET6 &&
|
||||
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, &addr->in6.sin6_addr))
|
||||
continue;
|
||||
@@ -141,6 +145,10 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
/* Not in cache in child, no go. */
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
return 0;
|
||||
|
||||
/* Not found, try the kernel */
|
||||
if (!updated)
|
||||
{
|
||||
|
||||
25
src/dbus.c
25
src/dbus.c
@@ -530,8 +530,8 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
union all_addr addr;
|
||||
time_t now = dnsmasq_time();
|
||||
unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
|
||||
|
||||
DBusMessageIter iter, array_iter;
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
@@ -599,6 +599,10 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr4))
|
||||
{
|
||||
if (!daemon->dhcp)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"DHCPv4 not configured");
|
||||
|
||||
if (ia_id != 0 || is_temporary)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"ia_id and is_temporary must be zero for IPv4 lease");
|
||||
@@ -609,16 +613,25 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
|
||||
{
|
||||
if (!daemon->doing_dhcp6)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"DHCPv6 not configured");
|
||||
|
||||
if (!(lease = lease6_find_by_addr(&addr.addr6, 128, 0)))
|
||||
lease = lease6_allocate(&addr.addr6,
|
||||
is_temporary ? LEASE_TA : LEASE_NA);
|
||||
lease_set_iaid(lease, ia_id);
|
||||
if (lease)
|
||||
lease_set_iaid(lease, ia_id);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
|
||||
if (!lease)
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"unable to allocate lease for IP address '%s'", ipaddr);
|
||||
|
||||
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
if (hw_len < 0)
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
@@ -641,7 +654,7 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
|
||||
static DBusMessage *dbus_del_lease(DBusMessage* message)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
struct dhcp_lease *lease = NULL;
|
||||
DBusMessageIter iter;
|
||||
const char *ipaddr;
|
||||
DBusMessage *reply;
|
||||
@@ -659,10 +672,10 @@ static DBusMessage *dbus_del_lease(DBusMessage* message)
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ipaddr);
|
||||
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr4))
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr4) && daemon->dhcp)
|
||||
lease = lease_find_by_addr(addr.addr4);
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr6) && daemon->doing_dhcp6)
|
||||
lease = lease6_find_by_addr(&addr.addr6, 128, 0);
|
||||
#endif
|
||||
else
|
||||
|
||||
@@ -709,7 +709,8 @@ static const struct opttab_t {
|
||||
{ "client-machine-id", 97, 0 },
|
||||
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "ipv6-only", 108, 4 | OT_DEC }, /* RFC 8925 */
|
||||
{ "ipv6-only", 108, 4 | OT_DEC }, /* RFC 8925 */
|
||||
{ "captive-portal", 114, OT_NAME }, /* RFC 8910 */
|
||||
{ "subnet-select", 118, OT_INTERNAL },
|
||||
{ "domain-search", 119, OT_RFC1035_NAME },
|
||||
{ "sip-server", 120, 0 },
|
||||
@@ -751,6 +752,7 @@ static const struct opttab_t opttab6[] = {
|
||||
{ "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
|
||||
{ "bootfile-url", 59, OT_NAME },
|
||||
{ "bootfile-param", 60, OT_CSTRING },
|
||||
{ "captive-portal", 103, OT_NAME }, /* RFC 8910 */
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -696,7 +696,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (taddr.s_addr == context->router.s_addr)
|
||||
if (taddr.s_addr == tmp->router.s_addr)
|
||||
return NULL;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
|
||||
@@ -127,6 +127,7 @@ int main (int argc, char **argv)
|
||||
This might be increased is EDNS packet size if greater than the minimum. */
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
daemon->pipe_to_parent = -1;
|
||||
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
|
||||
@@ -1080,8 +1081,6 @@ int main (int argc, char **argv)
|
||||
|
||||
pid = getpid();
|
||||
|
||||
daemon->pipe_to_parent = -1;
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
/* Using inotify, have to select a resolv file at startup */
|
||||
poll_resolv(1, 0, now);
|
||||
@@ -2033,9 +2032,24 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* The code in edns0.c qthat decorates queries with the source MAC address depends
|
||||
on the code in arp.c, which populates a cache with the contents of the ARP table
|
||||
using netlink. Since the child process can't use netlink, we pre-populate
|
||||
the cache with the ARP table entry for our source here, including a negative entry
|
||||
if there is nothing for our address in the ARP table.
|
||||
|
||||
When the edns0 code calls find_mac() in the child process, it will
|
||||
get the correct answer from the cache inherited from the parent
|
||||
without having to use netlink to consult the kernel ARP table.
|
||||
|
||||
edns0_needs_mac() simply calls find_mac if any EDNS0 options
|
||||
which need a MAC address are enabled. */
|
||||
|
||||
edns0_needs_mac(&tcp_addr, now);
|
||||
|
||||
if (pipe(pipefd) == -1)
|
||||
goto closeconandreturn; /* pipe failed */
|
||||
|
||||
|
||||
if ((p = fork()) == -1)
|
||||
{
|
||||
/* fork failed */
|
||||
|
||||
@@ -1109,7 +1109,7 @@ struct ping_result {
|
||||
|
||||
struct tftp_file {
|
||||
int refcount, fd;
|
||||
off_t size;
|
||||
off_t size, posn;
|
||||
dev_t dev;
|
||||
ino_t inode;
|
||||
char filename[];
|
||||
@@ -1124,7 +1124,7 @@ struct tftp_transfer {
|
||||
union mysockaddr peer;
|
||||
union all_addr source;
|
||||
int if_index;
|
||||
unsigned char opt_blocksize, opt_transize, opt_windowsize, opt_timeout, netascii, carrylf, backoff;
|
||||
unsigned char opt_blocksize, opt_transize, opt_windowsize, opt_timeout, netascii, carrylf, lastcarrylf, backoff;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *next;
|
||||
};
|
||||
@@ -1278,7 +1278,7 @@ extern struct daemon {
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
struct server *srv_save; /* Used for resend on DoD */
|
||||
void *srv_save; /* Used for resend on DoD and tftp prefetch */
|
||||
size_t packet_len; /* " " */
|
||||
int fd_save; /* " " */
|
||||
pid_t *tcp_pids;
|
||||
@@ -1918,6 +1918,7 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
|
||||
void edns0_needs_mac(union mysockaddr *addr, time_t now);
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *cacheable);
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
|
||||
10
src/edns0.c
10
src/edns0.c
@@ -265,6 +265,15 @@ static void encoder(unsigned char *in, char *out)
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
/* This function needs to call find_mac if any option which requires a MAC address is enabled
|
||||
and used below. If you add a new MAC consumer, modify this, otherwise your
|
||||
new EDNS0 option won't work in TCP mode. */
|
||||
void edns0_needs_mac(union mysockaddr *addr, time_t now)
|
||||
{
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX) || option_bool(OPT_ADD_MAC))
|
||||
find_mac(addr, NULL, 0, now);
|
||||
}
|
||||
|
||||
/* OPT_ADD_MAC = MAC is added (if available)
|
||||
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
|
||||
OPT_STRIP_MAC = MAC is removed */
|
||||
@@ -562,3 +571,4 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,13 @@ int iface_enumerate(int family, void *parm, callback_t callback)
|
||||
struct rtgenmsg g;
|
||||
} req;
|
||||
|
||||
/* The netlink socket is not available in child processes. */
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("BUG: called iface_enumerate() in child process"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
|
||||
@@ -1596,9 +1596,14 @@ static void get_context_tag(struct state *state, struct dhcp_context *context)
|
||||
|
||||
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
|
||||
{
|
||||
state->ia_type = opt6_type(opt);
|
||||
*ia_option = NULL;
|
||||
|
||||
/* must be a minimal option to check without stepping outside received packet. */
|
||||
if (opt6_ptr(opt, 4) > state->end)
|
||||
return 0;
|
||||
|
||||
state->ia_type = opt6_type(opt);
|
||||
|
||||
if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
|
||||
return 0;
|
||||
|
||||
@@ -1608,7 +1613,10 @@ static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio
|
||||
if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
|
||||
return 0;
|
||||
|
||||
*endp = opt6_ptr(opt, opt6_len(opt));
|
||||
/* Check we don't overflow the received packet. */
|
||||
if ((*endp = opt6_ptr(opt, opt6_len(opt))) > state->end)
|
||||
return 0;
|
||||
|
||||
state->iaid = opt6_uint(opt, 0, 4);
|
||||
*ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
|
||||
|
||||
|
||||
196
src/tftp.c
196
src/tftp.c
@@ -18,12 +18,12 @@
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
|
||||
static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client);
|
||||
static void handle_tftp(char *packet, time_t now, struct tftp_transfer *transfer, ssize_t len);
|
||||
static struct tftp_file *check_tftp_fileperm(char *packet, ssize_t *len, char *prefix, char *client);
|
||||
static void free_transfer(struct tftp_transfer *transfer);
|
||||
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2);
|
||||
static ssize_t tftp_err_oops(char *packet, const char *file);
|
||||
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
|
||||
static ssize_t get_block(struct tftp_transfer *transfer);
|
||||
static char *next(char **p, char *end);
|
||||
static void sanitise(char *buf);
|
||||
|
||||
@@ -41,10 +41,9 @@ static void sanitise(char *buf);
|
||||
#define ERR_ILL 4
|
||||
#define ERR_TID 5
|
||||
|
||||
static void tftp_request(struct listener *listen, time_t now)
|
||||
static void tftp_request(char *packet, ssize_t plen, struct listener *listen, time_t now)
|
||||
{
|
||||
ssize_t len;
|
||||
char *packet = daemon->packet;
|
||||
char *filename, *mode, *p, *end;
|
||||
union mysockaddr addr, peer;
|
||||
struct msghdr msg;
|
||||
@@ -87,12 +86,10 @@ static void tftp_request(struct listener *listen, time_t now)
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
/* packet buff is DNS name workspace. */
|
||||
iov.iov_base = packet;
|
||||
iov.iov_len = daemon->packet_buff_sz;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
iov.iov_len = plen;
|
||||
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
@@ -267,7 +264,7 @@ static void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
else
|
||||
{
|
||||
handle_tftp(now, transfer, len);
|
||||
handle_tftp(packet, now, transfer, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -501,17 +498,21 @@ static void tftp_request(struct listener *listen, time_t now)
|
||||
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
/* check permissions and open file */
|
||||
if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
|
||||
if ((transfer->file = check_tftp_fileperm(packet, &len, prefix, daemon->addrbuff)))
|
||||
{
|
||||
transfer->lastack = transfer->block;
|
||||
transfer->retransmit = now + transfer->timeout;
|
||||
/* This packet is may be the first data packet, but only if windowsize == 1
|
||||
To get windowsize greater then one requires an option negotiation,
|
||||
in which case this packet is the OACK. */
|
||||
if ((len = get_block(packet, transfer)) == -1)
|
||||
if ((len = get_block(transfer)) == -1)
|
||||
len = tftp_err_oops(packet, daemon->namebuff);
|
||||
else
|
||||
is_err = 0;
|
||||
{
|
||||
is_err = 0;
|
||||
/* get_block put the packet to send in a different buffer. */
|
||||
packet = daemon->packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,9 +535,9 @@ static void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client)
|
||||
static struct tftp_file *check_tftp_fileperm(char *packet, ssize_t *len, char *prefix, char *client)
|
||||
{
|
||||
char *packet = daemon->packet, *namebuff = daemon->namebuff;
|
||||
char *namebuff = daemon->namebuff;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *t;
|
||||
uid_t uid = geteuid();
|
||||
@@ -599,6 +600,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *c
|
||||
file->size = statbuf.st_size;
|
||||
file->dev = statbuf.st_dev;
|
||||
file->inode = statbuf.st_ino;
|
||||
file->posn = 0;
|
||||
file->refcount = 1;
|
||||
strcpy(file->filename, namebuff);
|
||||
return file;
|
||||
@@ -618,12 +620,15 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *c
|
||||
|
||||
void check_tftp_listeners(time_t now)
|
||||
{
|
||||
/* Use workspace to receive (small) request/ACK, to avoid overwriting precomputed reply */
|
||||
char *packet = daemon->workspacename;
|
||||
ssize_t plen = MAXDNAME * 2;
|
||||
struct listener *listener;
|
||||
struct tftp_transfer *transfer, *tmp, **up;
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
|
||||
tftp_request(listener, now);
|
||||
tftp_request(packet, plen, listener, now);
|
||||
|
||||
/* In single port mode, all packets come via port 69 and tftp_request() */
|
||||
if (!option_bool(OPT_SINGLE_PORT))
|
||||
@@ -634,26 +639,23 @@ void check_tftp_listeners(time_t now)
|
||||
socklen_t addr_len = sizeof(union mysockaddr);
|
||||
ssize_t len;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if ((len = recvfrom(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0, &peer.sa, &addr_len)) > 0)
|
||||
if ((len = recvfrom(transfer->sockfd, packet, plen, 0, &peer.sa, &addr_len)) > 0)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, (union mysockaddr *)&peer, NULL, transfer->sockfd);
|
||||
dump_packet_udp(DUMP_TFTP, (void *)packet, len, (union mysockaddr *)&peer, NULL, transfer->sockfd);
|
||||
#endif
|
||||
|
||||
if (sockaddr_isequal(&peer, &transfer->peer))
|
||||
handle_tftp(now, transfer, len);
|
||||
handle_tftp(packet, now, transfer, len);
|
||||
else
|
||||
{
|
||||
/* Wrong source address. See rfc1350 para 4. */
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL);
|
||||
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
|
||||
len = tftp_err(ERR_TID, packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL);
|
||||
while(retry_send(sendto(transfer->sockfd, packet, len, 0, &peer.sa, sa_len(&peer))));
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd);
|
||||
dump_packet_udp(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -673,7 +675,7 @@ void check_tftp_listeners(time_t now)
|
||||
endcon = 1;
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
if (get_block(daemon->packet, transfer) > 0)
|
||||
if (get_block(transfer) > 0)
|
||||
error = timeout = 1;
|
||||
}
|
||||
else if (difftime(now, transfer->retransmit) >= 0.0)
|
||||
@@ -682,41 +684,43 @@ void check_tftp_listeners(time_t now)
|
||||
bumps transfer->lastack and trips the retransmit timer so that we send the next block(s)
|
||||
here. */
|
||||
ssize_t len;
|
||||
unsigned int i, winsize;
|
||||
|
||||
transfer->retransmit += transfer->timeout + (1<<(transfer->backoff/2));
|
||||
transfer->backoff++;
|
||||
transfer->block = transfer->lastack;
|
||||
|
||||
if ((len = get_block(daemon->packet, transfer)) == 0)
|
||||
endcon = 1; /* got last ACK */
|
||||
else
|
||||
/* send a window'a worth of blocks unless we're retransmitting OACK */
|
||||
winsize = transfer->block ? transfer->windowsize : 1;
|
||||
|
||||
for (i = 0; i < winsize; i++, transfer->block++)
|
||||
{
|
||||
/* send a window'a worth of blocks unless we're retransmitting OACK */
|
||||
unsigned int i, winsize = transfer->block ? transfer->windowsize : 1;
|
||||
|
||||
for (i = 0; i < winsize && !endcon; i++, transfer->block++)
|
||||
if ((len = get_block(transfer)) == 0)
|
||||
{
|
||||
if (i != 0)
|
||||
len = get_block(daemon->packet, transfer);
|
||||
if (i == 0)
|
||||
endcon = 1; /* got last ACK */
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
len = tftp_err_oops(daemon->packet, transfer->file->filename);
|
||||
endcon = error = 1;
|
||||
}
|
||||
|
||||
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
|
||||
&transfer->peer, &transfer->source, transfer->if_index);
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, transfer->sockfd);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
len = tftp_err_oops(daemon->packet, transfer->file->filename);
|
||||
endcon = error = 1;
|
||||
}
|
||||
|
||||
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
|
||||
&transfer->peer, &transfer->source, transfer->if_index);
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, transfer->sockfd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* prefetch the block we'll probably need when we get an ACK. */
|
||||
if (!endcon)
|
||||
get_block(transfer);
|
||||
}
|
||||
|
||||
if (endcon)
|
||||
{
|
||||
strcpy(daemon->namebuff, transfer->file->filename);
|
||||
@@ -745,12 +749,11 @@ void check_tftp_listeners(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
/* packet in daemon->packet as this is called. */
|
||||
static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
static void handle_tftp(char *packet, time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
{
|
||||
struct ack {
|
||||
unsigned short op, block;
|
||||
} *mess = (struct ack *)daemon->packet;
|
||||
} *mess = (struct ack *)packet;
|
||||
|
||||
if (len >= (ssize_t)sizeof(struct ack))
|
||||
{
|
||||
@@ -774,7 +777,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
|
||||
transfer->ackprev = new;
|
||||
block = (((u32)transfer->block_hi) << 16) + (u32)new;
|
||||
|
||||
|
||||
/* Ignore duplicate ACKs and ACKs for blocks we've not yet sent. */
|
||||
if (block >= transfer->lastack &&
|
||||
block <= transfer->block)
|
||||
@@ -783,20 +786,23 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
transfer->retransmit = transfer->start = now;
|
||||
transfer->backoff = 0;
|
||||
transfer->lastack = block + 1;
|
||||
|
||||
|
||||
/* We have no easy function from block no. to file offset when
|
||||
expanding line breaks in netascii mode, so we update the offset here
|
||||
as each block is acknowledged. This explains why the window size must be
|
||||
one for a netascii transfer; to avoid the block no. doing anything
|
||||
other than incrementing by one. */
|
||||
if (transfer->netascii && block != 0)
|
||||
transfer->offset += transfer->blocksize - transfer->expansion;
|
||||
{
|
||||
transfer->offset += (off_t)transfer->blocksize - (off_t)transfer->expansion;
|
||||
transfer->lastcarrylf = transfer->carrylf;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ntohs(mess->op) == OP_ERR)
|
||||
{
|
||||
char *p = daemon->packet + sizeof(struct ack);
|
||||
char *end = daemon->packet + len;
|
||||
char *p = packet + sizeof(struct ack);
|
||||
char *end = packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
@@ -873,10 +879,6 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *
|
||||
} *mess = (struct errmess *)packet;
|
||||
ssize_t len, ret = 4;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
memset(packet, 0, daemon->packet_buff_sz);
|
||||
if (file)
|
||||
sanitise(file);
|
||||
|
||||
@@ -900,12 +902,10 @@ static ssize_t tftp_err_oops(char *packet, const char *file)
|
||||
}
|
||||
|
||||
/* return -1 for error, zero for done. */
|
||||
static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
static ssize_t get_block(struct tftp_transfer *transfer)
|
||||
{
|
||||
memset(packet, 0, daemon->packet_buff_sz);
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
static off_t saved_offset = 0;
|
||||
static ssize_t saved_len = 0;
|
||||
|
||||
if (transfer->block == 0)
|
||||
{
|
||||
@@ -914,8 +914,12 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
struct oackmess {
|
||||
unsigned short op;
|
||||
char data[];
|
||||
} *mess = (struct oackmess *)packet;
|
||||
|
||||
} *mess = (struct oackmess *)daemon->packet;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
memset(daemon->packet, 0, daemon->packet_buff_sz);
|
||||
|
||||
p = mess->data;
|
||||
mess->op = htons(OP_OACK);
|
||||
if (transfer->opt_blocksize)
|
||||
@@ -939,7 +943,7 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
p += (sprintf(p, "%u", (unsigned int)transfer->windowsize) + 1);
|
||||
}
|
||||
|
||||
return p - packet;
|
||||
return p - daemon->packet;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -947,7 +951,7 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
struct datamess {
|
||||
unsigned short op, block;
|
||||
unsigned char data[];
|
||||
} *mess = (struct datamess *)packet;
|
||||
} *mess = (struct datamess *)daemon->packet;
|
||||
|
||||
size_t size;
|
||||
|
||||
@@ -956,35 +960,49 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
|
||||
if (transfer->offset > transfer->file->size)
|
||||
return 0; /* finished */
|
||||
|
||||
|
||||
/* We may have a prefetched block already in the buffer. */
|
||||
if (daemon->srv_save == transfer && saved_offset == transfer->offset)
|
||||
return saved_len;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if ((size = transfer->file->size - transfer->offset) > (size_t)transfer->blocksize)
|
||||
size = (size_t)transfer->blocksize;
|
||||
|
||||
mess->op = htons(OP_DATA);
|
||||
mess->block = htons((unsigned short)(transfer->block));
|
||||
|
||||
if (size != 0 &&
|
||||
(lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
|
||||
!read_write(transfer->file->fd, mess->data, size, RW_READ)))
|
||||
return -1;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
if (transfer->file->posn != transfer->offset &&
|
||||
lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1)
|
||||
return -1;
|
||||
|
||||
if (!read_write(transfer->file->fd, mess->data, size, RW_READ))
|
||||
return -1;
|
||||
|
||||
transfer->file->posn = transfer->offset + size;
|
||||
}
|
||||
|
||||
/* Map '\n' to CR-LF in netascii mode */
|
||||
if (transfer->netascii)
|
||||
{
|
||||
size_t i;
|
||||
int newcarrylf;
|
||||
|
||||
/* Map '\n' to CR-LF in netascii mode */
|
||||
transfer->expansion = transfer->carrylf = 0;
|
||||
|
||||
transfer->expansion = 0;
|
||||
|
||||
for (i = 0, newcarrylf = 0; i < size; i++)
|
||||
if (mess->data[i] == '\n' && (i != 0 || !transfer->carrylf))
|
||||
for (i = 0; i < size; i++)
|
||||
if (mess->data[i] == '\n' && (i != 0 || !transfer->lastcarrylf))
|
||||
{
|
||||
transfer->expansion++;
|
||||
|
||||
if (size != transfer->blocksize)
|
||||
size++; /* room in this block */
|
||||
else if (i == size - 1)
|
||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||
transfer->carrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||
|
||||
/* make space and insert CR */
|
||||
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
||||
@@ -992,11 +1010,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
transfer->carrylf = newcarrylf;
|
||||
}
|
||||
|
||||
return size + 4;
|
||||
daemon->srv_save = transfer;
|
||||
saved_offset = transfer->offset;
|
||||
saved_len = size + 4;
|
||||
|
||||
return saved_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user