import of dnsmasq-2.51.tar.gz

This commit is contained in:
Simon Kelley
2009-10-13 17:49:32 +01:00
parent 77e94da7bb
commit 1f15b81d61
34 changed files with 2729 additions and 2194 deletions

View File

@@ -226,7 +226,7 @@ char *cache_get_name(struct crec *crecp)
{
if (crecp->flags & F_BIGNAME)
return crecp->name.bname->name;
else if (crecp->flags & F_DHCP)
else if (crecp->flags & (F_DHCP | F_CONFIG))
return crecp->name.namep;
return crecp->name.sname;
@@ -366,7 +366,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
log_query(flags | F_UPSTREAM, name, addr, NULL);
/* CONFIG bit no needed except for logging */
/* CONFIG bit means something else when stored in cache entries */
flags &= ~F_CONFIG;
/* if previous insertion failed give up now. */
@@ -693,10 +693,10 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
if (!nameexists)
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache->name.sname, a->target) &&
(lookup = whine_malloc(sizeof(struct crec) + strlen(a->alias)+1-SMALLDNAME)))
(lookup = whine_malloc(sizeof(struct crec))))
{
lookup->flags = F_FORWARD | F_IMMORTAL | F_HOSTS | F_CNAME;
strcpy(lookup->name.sname, a->alias);
lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
lookup->name.namep = a->alias;
lookup->addr.cname.cache = cache;
lookup->addr.cname.uid = index;
cache_hash(lookup);
@@ -821,35 +821,38 @@ static int read_hostsfile(char *filename, int index, int cache_size)
while (atnl == 0)
{
struct crec *cache;
int fqdn;
int fqdn, nomem;
char *canon;
if ((atnl = gettok(f, token)) == EOF)
break;
fqdn = !!strchr(token, '.');
if (canonicalise(token))
if ((canon = canonicalise(token, &nomem)))
{
/* If set, add a version of the name with a default domain appended */
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcpy(cache->name.sname, canon);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcpy(cache->name.sname, canon);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
free(canon);
}
else
else if (!nomem)
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
@@ -1103,7 +1106,7 @@ void cache_add_dhcp_entry(char *host_name,
if (aliasc)
{
aliasc->flags = F_FORWARD | F_DHCP | F_CNAME;
aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
if (ttd == 0)
aliasc->flags |= F_IMMORTAL;
else
@@ -1285,12 +1288,12 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
dest = "<CNAME>";
}
if (flags & F_DHCP)
if (flags & F_CONFIG)
source = "config";
else if (flags & F_DHCP)
source = "DHCP";
else if (flags & F_HOSTS)
source = arg;
else if (flags & F_CONFIG)
source = "config";
else if (flags & F_UPSTREAM)
source = "reply";
else if (flags & F_SERVER)

View File

@@ -14,13 +14,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.50"
#define VERSION "2.51"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 10 /* or 10 seconds */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
@@ -126,6 +128,9 @@ HAVE_TFTP
HAVE_DHCP
define this to get dnsmasq's DHCP server.
HAVE_SCRIPT
define this to get the ability to call scripts on lease-change
HAVE_GETOPT_LONG
define this if you have GNU libc or GNU getopt.
@@ -162,6 +167,7 @@ NOTES:
/* platform independent options- uncomment to enable */
#define HAVE_DHCP
#define HAVE_TFTP
#define HAVE_SCRIPT
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
@@ -175,6 +181,13 @@ NOTES:
#undef HAVE_DHCP
#endif
/* Allow scripts to be disabled with COPTS=-DNO_SCRIPT */
#ifdef NO_SCRIPT
#undef HAVE_SCRIPT
#endif
/* platform dependent options. */
/* Must preceed __linux__ since uClinux defines __linux__ too. */
@@ -273,3 +286,8 @@ NOTES:
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
#endif
/* Can't do scripts without fork */
#ifdef NOFORK
# undef HAVE_SCRIPT
#endif

View File

@@ -390,16 +390,25 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
}
}
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr)
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
const char *action_str;
char *action_str, *addr, *mac = daemon->namebuff;
unsigned char *p;
int i;
if (!connection)
return;
if (!hostname)
hostname = "";
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(mac, p, i);
if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD)
@@ -409,6 +418,8 @@ void emit_dbus_signal(int action, char *mac, char *hostname, char *addr)
else
return;
addr = inet_ntoa(lease->addr);
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return;

View File

@@ -754,6 +754,8 @@ void dhcp_read_ethers(void)
while (fgets(buff, MAXDNAME, f))
{
char *host = NULL;
lineno++;
while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
@@ -792,19 +794,28 @@ void dhcp_read_ethers(void)
}
else
{
if (!canonicalise(ip))
int nomem;
if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
{
my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
if (!nomem)
my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
free(host);
continue;
}
flags = CONFIG_NAME;
for (config = daemon->dhcp_conf; config; config = config->next)
if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip))
if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
break;
}
if (config && (config->flags & CONFIG_FROM_ETHERS))
{
my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
continue;
}
if (!config)
{
for (config = daemon->dhcp_conf; config; config = config->next)
@@ -834,10 +845,8 @@ void dhcp_read_ethers(void)
if (flags & CONFIG_NAME)
{
if ((config->hostname = whine_malloc(strlen(ip)+1)))
strcpy(config->hostname, ip);
else
config->flags &= ~CONFIG_NAME;
config->hostname = host;
host = NULL;
}
if (flags & CONFIG_ADDR)
@@ -856,6 +865,9 @@ void dhcp_read_ethers(void)
config->hwaddr->next = NULL;
}
count++;
free(host);
}
fclose(f);
@@ -945,7 +957,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
for this address. If it has a domain part, that must match the set domain and
it gets stripped. */
it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
so check here that the domain name is legal as a hostname. */
char *host_from_dns(struct in_addr addr)
{
struct crec *lookup;
@@ -963,7 +976,7 @@ char *host_from_dns(struct in_addr addr)
hostname[255] = 0;
d1 = strip_hostname(hostname);
d2 = get_domain(addr);
if (d1 && (!d2 || hostname_isequal(d1, d2)))
if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
hostname = NULL;
}

View File

@@ -45,11 +45,16 @@ static char *compile_opts =
"no-"
#endif
"DHCP "
#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
"no-scripts "
#endif
#ifndef HAVE_TFTP
"no-"
#endif
"TFTP";
static volatile pid_t pid = 0;
static volatile int pipewrite;
@@ -68,7 +73,7 @@ int main (int argc, char **argv)
struct iname *if_tmp;
int piperead, pipefd[2], err_pipe[2];
struct passwd *ent_pw = NULL;
#ifdef HAVE_DHCP
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
uid_t script_uid = 0;
gid_t script_gid = 0;
#endif
@@ -202,7 +207,7 @@ int main (int argc, char **argv)
if (daemon->port != 0)
pre_allocate_sfds();
#ifdef HAVE_DHCP
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
/* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
{
@@ -352,7 +357,7 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#if defined(HAVE_DHCP) && !defined(NO_FORK)
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
if (daemon->dhcp && daemon->lease_change_command)
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
@@ -603,7 +608,7 @@ int main (int argc, char **argv)
bump_maxfd(piperead, &maxfd);
#ifdef HAVE_DHCP
# ifndef NO_FORK
# ifdef HAVE_SCRIPT
while (helper_buf_empty() && do_script_run(now));
if (!helper_buf_empty())
@@ -674,7 +679,7 @@ int main (int argc, char **argv)
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now);
# ifndef NO_FORK
# ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
helper_write();
# endif
@@ -857,7 +862,7 @@ static void async_event(int pipe, time_t now)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
#if defined(HAVE_DHCP) && !defined(NO_FORK)
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
/* handle pending lease transitions */
if (daemon->helperfd != -1)
{

View File

@@ -30,6 +30,7 @@
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef __APPLE__
@@ -55,7 +56,6 @@
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if defined(HAVE_SOLARIS_NETWORK)
#include <sys/sockio.h>
@@ -335,7 +335,7 @@ struct server {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int dhcp_ok;
int dhcp_ok, mtu;
struct irec *next;
};
@@ -410,9 +410,9 @@ struct dhcp_lease {
#endif
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr, override;
unsigned char *vendorclass, *userclass;
unsigned int vendorclass_len, userclass_len;
struct in_addr addr, override, giaddr;
unsigned char *vendorclass, *userclass, *supplied_hostname;
unsigned int vendorclass_len, userclass_len, supplied_hostname_len;
int last_interface;
struct dhcp_lease *next;
};
@@ -626,6 +626,7 @@ extern struct daemon {
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
struct pxe_service *pxe_services;
int enable_pxe;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max;
@@ -646,6 +647,8 @@ extern struct daemon {
struct irec *interfaces;
struct listener *listeners;
struct server *last_server;
time_t forwardtime;
int forwardcount;
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
struct randfd *rfd_save; /* " " */
@@ -719,8 +722,8 @@ size_t resize_packet(HEADER *header, size_t plen,
/* util.c */
void rand_init(void);
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
int legal_hostname(char *c);
char *canonicalise(char *s, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
void *safe_malloc(size_t size);
void safe_pipe(int *fd, int read_noblock);
@@ -863,7 +866,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr);
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
#endif
/* helper.c */

View File

@@ -262,10 +262,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (type != 0 || (daemon->options & OPT_ORDER))
start = daemon->servers;
else if (!(start = daemon->last_server))
else if (!(start = daemon->last_server) ||
daemon->forwardcount++ > FORWARD_TEST ||
difftime(now, daemon->forwardtime) > FORWARD_TIME)
{
start = daemon->servers;
forward->forwardall = 1;
daemon->forwardcount = 0;
daemon->forwardtime = now;
}
}
}

View File

@@ -28,15 +28,15 @@
main process.
*/
#if defined(HAVE_DHCP) && !defined(NO_FORK)
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
static void my_setenv(const char *name, const char *value, int *error);
struct script_data
{
unsigned char action, hwaddr_len, hwaddr_type;
unsigned char clid_len, hostname_len, uclass_len, vclass_len;
struct in_addr addr;
unsigned char clid_len, hostname_len, uclass_len, vclass_len, shost_len;
struct in_addr addr, giaddr;
unsigned int remaining_time;
#ifdef HAVE_BROKEN_RTC
unsigned int length;
@@ -101,7 +101,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
main process can return. */
for (max_fd--; max_fd > 0; max_fd--)
for (max_fd--; max_fd >= 0; max_fd--)
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
close(max_fd);
@@ -155,7 +155,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
sprintf(daemon->dhcp_buff2, "%lu ", (unsigned long)data.expires);
#endif
if (!read_write(pipefd[0], buf, data.hostname_len + data.uclass_len + data.vclass_len, 1))
if (!read_write(pipefd[0], buf,
data.hostname_len + data.uclass_len + data.vclass_len + data.shost_len, 1))
continue;
/* possible fork errors are all temporary resource problems */
@@ -232,6 +233,19 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
}
}
if (data.shost_len != 0)
{
buf[data.shost_len - 1] = 0; /* don't trust zero-term */
/* cannot have = chars in env - truncate if found . */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv("DNSMASQ_SUPPLIED_HOSTNAME", (char *)buf, &err);
buf += data.shost_len;
}
if (data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
@@ -240,7 +254,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char *dot;
hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0;
if (!canonicalise(hostname))
if (!legal_hostname(hostname))
hostname = NULL;
else if ((dot = strchr(hostname, '.')))
{
@@ -285,16 +299,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{
unsigned char *p;
size_t size;
int i;
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0;
unsigned int uclass_len = 0, shost_len = 0;
#ifdef HAVE_DBUS
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(daemon->namebuff, p, i);
emit_dbus_signal(action, daemon->namebuff, hostname ? hostname : "", inet_ntoa(lease->addr));
#endif
/* no script */
if (daemon->helperfd == -1)
return;
@@ -303,12 +310,14 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
vclass_len = lease->vendorclass_len;
if (lease->userclass)
uclass_len = lease->userclass_len;
if (lease->supplied_hostname)
shost_len = lease->supplied_hostname_len;
if (lease->clid)
clid_len = lease->clid_len;
if (hostname)
hostname_len = strlen(hostname) + 1;
size = sizeof(struct script_data) + clid_len + vclass_len + uclass_len + hostname_len;
size = sizeof(struct script_data) + clid_len + vclass_len + uclass_len + shost_len + hostname_len;
if (size > buf_size)
{
@@ -332,8 +341,10 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->clid_len = clid_len;
buf->vclass_len = vclass_len;
buf->uclass_len = uclass_len;
buf->shost_len = shost_len;
buf->hostname_len = hostname_len;
buf->addr = lease->addr;
buf->giaddr = lease->giaddr;
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
buf->interface[0] = 0;
#ifdef HAVE_LINUX_NETWORK
@@ -372,14 +383,17 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
memcpy(p, lease->userclass, uclass_len);
p += uclass_len;
}
/* substitute * for space: spaces are allowed in hostnames (for DNS-SD)
and are likley to be a security hole in most scripts. */
for (i = 0; i < (int)hostname_len; i++)
if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ')
*(p++) = '*';
else
*(p++) = hostname[i];
if (shost_len != 0)
{
memcpy(p, lease->supplied_hostname, shost_len);
p += shost_len;
}
if (hostname_len != 0)
{
memcpy(p, hostname, hostname_len);
p += hostname_len;
}
bytes_in_buf = p - (unsigned char *)buf;
}

View File

@@ -42,14 +42,20 @@ void lease_init(time_t now)
initial state of the database. If leasefile-ro is
set without a script, we just do without any
lease database. */
if (!daemon->lease_change_command)
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command)
{
file_dirty = dns_dirty = 0;
return;
strcpy(daemon->dhcp_buff, daemon->lease_change_command);
strcat(daemon->dhcp_buff, " init");
leasestream = popen(daemon->dhcp_buff, "r");
}
strcpy(daemon->dhcp_buff, daemon->lease_change_command);
strcat(daemon->dhcp_buff, " init");
leasestream = popen(daemon->dhcp_buff, "r");
else
#endif
{
file_dirty = dns_dirty = 0;
return;
}
}
else
{
@@ -100,19 +106,14 @@ void lease_init(time_t now)
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
{
char *p;
/* unprotect spaces */
for (p = strchr(daemon->dhcp_buff, '*'); p; p = strchr(p, '*'))
*p = ' ';
lease_set_hostname(lease, daemon->dhcp_buff, 0);
}
lease_set_hostname(lease, daemon->dhcp_buff, 0);
/* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */
lease->new = lease->changed = 0;
}
#ifdef HAVE_SCRIPT
if (!daemon->lease_stream)
{
int rc = 0;
@@ -133,6 +134,7 @@ void lease_init(time_t now)
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
}
}
#endif
/* Some leases may have expired */
file_dirty = 0;
@@ -173,7 +175,6 @@ void lease_update_file(time_t now)
struct dhcp_lease *lease;
time_t next_event;
int i, err = 0;
char *p;
if (file_dirty != 0 && daemon->lease_stream)
{
@@ -199,15 +200,8 @@ void lease_update_file(time_t now)
}
ourprintf(&err, " %s ", inet_ntoa(lease->addr));
/* substitute * for space: "*" is an illegal name, as is " " */
if (lease->hostname)
for (p = lease->hostname; *p; p++)
ourprintf(&err, "%c", *p == ' ' ? '*' : *p);
else
ourprintf(&err, "*");
ourprintf(&err, " ");
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0)
{
for (i = 0; i < lease->clid_len - 1; i++)
@@ -550,7 +544,7 @@ int do_script_run(time_t now)
/* If the lease still has an old_hostname, do the "old" action on that first */
if (lease->old_hostname)
{
#ifndef NO_FORK
#ifdef HAVE_SCRIPT
queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
#endif
free(lease->old_hostname);
@@ -560,8 +554,11 @@ int do_script_run(time_t now)
else
{
kill_name(lease);
#ifndef NO_FORK
#ifdef HAVE_SCRIPT
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
#endif
#ifdef HAVE_DBUS
emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
#endif
old_leases = lease->next;
@@ -569,6 +566,7 @@ int do_script_run(time_t now)
free(lease->clid);
free(lease->vendorclass);
free(lease->userclass);
free(lease->supplied_hostname);
free(lease);
return 1;
@@ -579,7 +577,7 @@ int do_script_run(time_t now)
for (lease = leases; lease; lease = lease->next)
if (lease->old_hostname)
{
#ifndef NO_FORK
#ifdef HAVE_SCRIPT
queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
#endif
free(lease->old_hostname);
@@ -591,9 +589,13 @@ int do_script_run(time_t now)
if (lease->new || lease->changed ||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
{
#ifndef NO_FORK
#ifdef HAVE_SCRIPT
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif
#ifdef HAVE_DBUS
emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname);
#endif
lease->new = lease->changed = lease->aux_changed = 0;
@@ -603,7 +605,10 @@ int do_script_run(time_t now)
free(lease->userclass);
lease->userclass = NULL;
free(lease->supplied_hostname);
lease->supplied_hostname = NULL;
return 1;
}

View File

@@ -119,7 +119,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
union mysockaddr *addr, struct in_addr netmask)
{
struct irec *iface;
int fd;
int fd, mtu = 0, loopback;
struct ifreq ifr;
int dhcp_ok = 1;
struct iname *tmp;
@@ -142,12 +142,17 @@ static int iface_allowed(struct irec **irecp, int if_index,
}
return 0;
}
loopback = ifr.ifr_flags & IFF_LOOPBACK;
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
close(fd);
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */
if (daemon->if_names && (ifr.ifr_flags & IFF_LOOPBACK))
if (daemon->if_names && loopback)
{
struct iname *lo;
for (lo = daemon->if_names; lo; lo = lo->next)
@@ -188,6 +193,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
iface->addr = *addr;
iface->netmask = netmask;
iface->dhcp_ok = dhcp_ok;
iface->mtu = mtu;
iface->next = *irecp;
*irecp = iface;
return 1;

View File

@@ -406,6 +406,7 @@ static const struct {
{ "domain-search", 119, 0 },
{ "sip-server", 120, 0 },
{ "classless-static-route", 121, 0 },
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
{ NULL, 0, 0 }
};
@@ -530,13 +531,24 @@ static char *split(char *s)
return split_chr(s, ',');
}
static int canonicalise_opt(char *s)
static char *canonicalise_opt(char *s)
{
char *ret;
int nomem;
if (!s)
return 0;
unhide_metas(s);
return canonicalise(s);
if (!(ret = canonicalise(s, &nomem)) && nomem)
{
if (mem_recover)
longjmp(mem_jmp, 1);
else
die(_("could not get memory"), NULL, EC_NOMEM);
}
return ret;
}
static int atoi_check(char *a, int *res)
@@ -646,7 +658,7 @@ static void display_opts(void)
printf(_("Known DHCP options:\n"));
for (i = 0; opttab[i].name; i++)
if (opttab[i].size != OT_INTERNAL)
if (!(opttab[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab[i].val, opttab[i].name);
}
@@ -684,7 +696,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (strstr(arg, "option:") == arg)
{
for (i = 0; opttab[i].name; i++)
if (opttab[i].size != OT_INTERNAL &&
if (!(opttab[i].size & OT_INTERNAL) &&
strcasecmp(opttab[i].name, arg+7) == 0)
{
new->opt = opttab[i].val;
@@ -873,7 +885,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
while (arg && *arg)
{
if (!canonicalise_opt(arg))
char *dom;
if (!(dom = arg = canonicalise_opt(arg)))
{
problem = _("bad domain in dhcp-option");
break;
@@ -898,7 +911,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
arg++;
}
*q++ = 0;
free(dom);
/* Now tail-compress using earlier names. */
newlen = q - p;
for (tail = p + len; *tail; tail += (*tail) + 1)
@@ -1018,25 +1032,51 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
DIR *dir_stream;
struct dirent *ent;
char *directory, *path;
struct list {
char *suffix;
struct list *next;
} *ignore_suffix = NULL, *li;
comma = split(arg);
if (!(directory = opt_string_alloc(arg)))
break;
for (arg = comma; arg; arg = comma)
{
comma = split(arg);
li = opt_malloc(sizeof(struct list));
li->next = ignore_suffix;
ignore_suffix = li;
/* Have to copy: buffer is overwritten */
li->suffix = opt_string_alloc(arg);
};
if (!(dir_stream = opendir(directory)))
die(_("cannot access directory %s: %s"), directory, EC_FILE);
while ((ent = readdir(dir_stream)))
{
size_t len = strlen(ent->d_name);
struct stat buf;
/* ignore emacs backups and dotfiles */
/* ignore emacs backups and dotfiles */
if (len == 0 ||
ent->d_name[len - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
ent->d_name[0] == '.')
continue;
for (li = ignore_suffix; li; li = li->next)
{
/* check for proscribed suffices */
size_t ls = strlen(li->suffix);
if (len > ls &&
strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
break;
}
if (li)
continue;
path = opt_malloc(strlen(directory) + len + 2);
strcpy(path, directory);
strcat(path, "/");
@@ -1055,6 +1095,13 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
closedir(dir_stream);
free(directory);
for(; ignore_suffix; ignore_suffix = li)
{
li = ignore_suffix->next;
free(ignore_suffix->suffix);
free(ignore_suffix);
}
break;
}
@@ -1127,32 +1174,32 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
int pref = 1;
struct mx_srv_record *new;
char *name, *target = NULL;
if ((comma = split(arg)))
{
char *prefstr;
if ((prefstr=split(comma)) && !atoi_check16(prefstr, &pref))
if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
problem = _("bad MX preference");
}
if (!canonicalise_opt(arg) || (comma && !canonicalise_opt(comma)))
if (!(name = canonicalise_opt(arg)) ||
(comma && !(target = canonicalise_opt(comma))))
problem = _("bad MX name");
new = opt_malloc(sizeof(struct mx_srv_record));
new->next = daemon->mxnames;
daemon->mxnames = new;
new->issrv = 0;
new->name = opt_string_alloc(arg);
new->target = opt_string_alloc(comma); /* may be NULL */
new->name = name;
new->target = target; /* may be NULL */
new->weight = pref;
break;
}
case 't': /* --mx-target */
if (!canonicalise_opt(arg))
if (!(daemon->mxtarget = canonicalise_opt(arg)))
problem = _("bad MX target");
else
daemon->mxtarget = opt_string_alloc(arg);
break;
#ifdef HAVE_DHCP
@@ -1161,8 +1208,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
case '6': /* --dhcp-script */
# ifdef NO_FORK
# if defined(NO_FORK)
problem = _("cannot run scripts under uClinux");
# elif !defined(HAVE_SCRIPT)
problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
# else
daemon->lease_change_command = opt_string_alloc(arg);
# endif
@@ -1186,12 +1235,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
daemon->options |= OPT_RESOLV_DOMAIN;
else
{
char *d;
comma = split(arg);
if (!canonicalise_opt(arg))
if (!(d = canonicalise_opt(arg)))
option = '?';
else
{
char *d = opt_string_alloc(arg);
if (comma)
{
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
@@ -1346,10 +1395,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0)
domain = "";
else if (!canonicalise_opt(arg) && strlen(arg) != 0)
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
option = '?';
else
domain = opt_string_alloc(arg); /* NULL if strlen is zero */
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
serv->next = newlist;
@@ -1662,7 +1709,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (!(a[k] = split(a[k-1])))
break;
if (option == '?' || (k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
option = '?';
else if (strcmp(a[1], "static") == 0)
{
@@ -1860,15 +1907,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->flags |= CONFIG_DISABLE;
else
{
int len = strlen(a[j]) + 1;
if (!canonicalise_opt(a[j]))
if (!(new->hostname = canonicalise_opt(a[j])) ||
!legal_hostname(new->hostname))
problem = _("bad DHCP host name");
else if ((new->hostname = opt_malloc(len)))
{
new->flags |= CONFIG_NAME;
strcpy(new->hostname, a[j]);
new->domain = NULL;
}
else
new->flags |= CONFIG_NAME;
new->domain = NULL;
}
}
else
@@ -1983,6 +2027,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->next = daemon->dhcp_opts;
daemon->dhcp_opts = new;
daemon->enable_pxe = 1;
}
break;
@@ -2051,6 +2096,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
s->next = new;
}
daemon->enable_pxe = 1;
break;
}
}
@@ -2243,19 +2289,20 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case LOPT_INTNAME: /* --interface-name */
{
struct interface_name *new, **up;
char *domain = NULL;
comma = split(arg);
if (!comma || !canonicalise_opt(arg))
if (!comma || !(domain = canonicalise_opt(arg)))
problem = _("bad interface name");
new = opt_malloc(sizeof(struct interface_name));
new->next = NULL;
/* Add to the end of the list, so that first name
of an interface is used for PTR lookups. */
for (up = &daemon->int_names; *up; up = &((*up)->next));
*up = new;
new->name = opt_string_alloc(arg);
new->name = domain;
new->intr = opt_string_alloc(comma);
break;
}
@@ -2268,14 +2315,22 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
option = '?';
else
{
for (new = daemon->cnames; new; new = new->next)
if (hostname_isequal(new->alias, arg))
problem = _("duplicate CNAME");
new = opt_malloc(sizeof(struct cname));
new->next = daemon->cnames;
daemon->cnames = new;
new->alias = opt_string_alloc(arg);
new->target = opt_string_alloc(comma);
char *alias = canonicalise_opt(arg);
char *target = canonicalise_opt(comma);
if (!alias || !target)
problem = _("bad CNAME");
else
{
for (new = daemon->cnames; new; new = new->next)
if (hostname_isequal(new->alias, arg))
problem = _("duplicate CNAME");
new = opt_malloc(sizeof(struct cname));
new->next = daemon->cnames;
daemon->cnames = new;
new->alias = alias;
new->target = target;
}
}
break;
}
@@ -2283,19 +2338,21 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case LOPT_PTR: /* --ptr-record */
{
struct ptr_record *new;
char *dom, *target = NULL;
comma = split(arg);
if (!canonicalise_opt(arg))
if (!(dom = canonicalise_opt(arg)) ||
(comma && !(target = canonicalise_opt(comma))))
problem = _("bad PTR record");
new = opt_malloc(sizeof(struct ptr_record));
new->next = daemon->ptr;
daemon->ptr = new;
new->name = opt_string_alloc(arg);
new->ptr = NULL;
if (comma)
new->ptr = opt_string_alloc(comma);
else
{
new = opt_malloc(sizeof(struct ptr_record));
new->next = daemon->ptr;
daemon->ptr = new;
new->name = dom;
new->ptr = target;
}
break;
}
@@ -2305,6 +2362,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
int k = 0;
struct naptr *new;
int order, pref;
char *name, *replace = NULL;
if ((a[0] = arg))
for (k = 1; k < 7; k++)
@@ -2313,22 +2371,21 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (k < 6 ||
!canonicalise_opt(a[0]) ||
!(name = canonicalise_opt(a[0])) ||
!atoi_check16(a[1], &order) ||
!atoi_check16(a[2], &pref) ||
(k == 7 && !canonicalise_opt(a[6])))
(k == 7 && !(replace = canonicalise_opt(a[6]))))
problem = _("bad NAPTR record");
else
{
new = opt_malloc(sizeof(struct naptr));
new->next = daemon->naptr;
daemon->naptr = new;
new->name = opt_string_alloc(a[0]);
new->name = name;
new->flags = opt_string_alloc(a[3]);
new->services = opt_string_alloc(a[4]);
new->regexp = opt_string_alloc(a[5]);
if (k == 7)
new->replace = opt_string_alloc(a[6]);
new->replace = replace;
new->order = order;
new->pref = pref;
}
@@ -2345,12 +2402,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
gen_prob = _("TXT record string too long");
if (!canonicalise_opt(arg))
{
problem = _("bad TXT record");
break;
}
if ((q = (unsigned char *)comma))
while (1)
{
@@ -2394,7 +2445,13 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
/* ensure arg is terminated */
if (comma)
*comma = 0;
new->name = opt_string_alloc(arg);
if (!(new->name = canonicalise_opt(arg)))
{
problem = _("bad TXT record");
break;
}
break;
}
@@ -2406,19 +2463,16 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
comma = split(arg);
if (!canonicalise_opt(arg))
if (!(name = canonicalise_opt(arg)))
problem = _("bad SRV record");
name = opt_string_alloc(arg);
if (comma)
{
arg = comma;
comma = split(arg);
if (!canonicalise_opt(arg))
problem = _("bad SRV target");
if (!(target = canonicalise_opt(arg))
) problem = _("bad SRV target");
target = opt_string_alloc(arg);
if (comma)
{
arg = comma;
@@ -2683,7 +2737,7 @@ void reread_dhcp(void)
}
one_file(daemon->dhcp_hosts_file, 1, LOPT_BANK);
my_syslog(LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
}
if (daemon->dhcp_opts_file)
@@ -2714,7 +2768,7 @@ void reread_dhcp(void)
}
one_file(daemon->dhcp_opts_file, 1, LOPT_OPTS);
my_syslog(LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
}
}
#endif
@@ -2898,8 +2952,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
continue;
if ((token = strtok(NULL, " \t\n\r")) &&
canonicalise_opt(token) &&
(daemon->domain_suffix = opt_string_alloc(token)))
(daemon->domain_suffix = canonicalise_opt(token)))
break;
}

View File

@@ -138,7 +138,8 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
for(j=0; j<l; j++, p++)
if (isExtract)
{
if (legal_char(*p))
unsigned char c = *p;
if (isascii(c) && !iscntrl(c) && c != '.')
*cp++ = *p;
else
return 0;

View File

@@ -415,7 +415,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
if (match_netid(id_list->list, netid, 0))
message = _("disabled");
message = _("ignored");
if (!message)
{
@@ -536,7 +536,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
*pq = 0;
if (canonicalise(daemon->dhcp_buff))
if (legal_hostname(daemon->dhcp_buff))
offer_hostname = client_hostname = daemon->dhcp_buff;
}
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
@@ -550,7 +550,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
borken_opt = 1;
else
daemon->dhcp_buff[len] = 0;
if (canonicalise(daemon->dhcp_buff))
if (legal_hostname(daemon->dhcp_buff))
client_hostname = daemon->dhcp_buff;
}
@@ -708,7 +708,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clid = NULL;
/* Check if client is PXE client. */
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
if (daemon->enable_pxe &&
(opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
{
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
@@ -728,6 +729,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned char save71[4];
struct dhcp_opt opt71;
if (ignore)
return 0;
if (layer & 0x8000)
{
my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
@@ -807,8 +811,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
prune_vendor_opts(netid);
do_encap_opts(pxe_opts(pxearch, netid), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", NULL, emac, emac_len, iface_name, "proxy", mess->xid);
return dhcp_packet_size(mess, netid, agent_id, real_end);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy" : "proxy-ignored", mess->xid);
return ignore ? 0 : dhcp_packet_size(mess, netid, agent_id, real_end);
}
}
}
@@ -1133,6 +1137,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
if (do_classes)
{
if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr;
lease->changed = 1;
/* copy user-class and vendor class into new lease, for the script */
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
@@ -1162,6 +1169,18 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease->vendorclass_len = len+1;
}
}
if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
free(lease->supplied_hostname);
if ((lease->supplied_hostname = whine_malloc(len+1)))
{
memcpy(lease->supplied_hostname, ucp, len);
lease->supplied_hostname[len] = 0;
lease->supplied_hostname_len = len+1;
}
}
}
if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
@@ -1538,7 +1557,6 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
/* move agent_id back down to the end of the packet */
if (agent_id)
{
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
memmove(p, agent_id, real_end - agent_id);
p += real_end - agent_id;
memset(p, 0, real_end - p); /* in case of overlap */
@@ -1547,9 +1565,8 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
/* We do logging too */
if (netid && (daemon->options & OPT_LOG_OPTS))
{
char *p = daemon->namebuff;
*p = 0;
for (; netid; netid = netid->next)
char *s = daemon->namebuff;
for (*s = 0; netid; netid = netid->next)
{
/* kill dupes. */
for (n = netid->next; n; n = n->next)
@@ -1558,13 +1575,12 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
if (!n)
{
strncat (p, netid->net, MAXDNAME);
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
if (netid->next)
strncat (p, ", ", MAXDNAME);
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
}
}
p[MAXDNAME - 1] = 0;
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), p);
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
}
/* add END options to the regions. */
@@ -2074,21 +2090,26 @@ static void do_options(struct dhcp_context *context,
}
else
/* Use the values of the relevant options if no dhcp-boot given and
they're not explicitly asked for as options. */
they're not explicitly asked for as options. OPTION_END is used
as an internal way to specify siaddr without using dhcp-boot, for use in
dhcp-optsfile. */
{
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && mess->file[0] == 0 &&
(opt = option_find2(netid, config_opts, OPTION_FILENAME)))
(opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
{
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
done_file = 1;
}
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
(opt = option_find2(netid, config_opts, OPTION_SNAME)))
(opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
{
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
done_server = 1;
}
if ((opt = option_find2(netid, config_opts, OPTION_END)))
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
}
/* We don't want to do option-overload for BOOTP, so make the file and sname

View File

@@ -46,12 +46,13 @@ void tftp_request(struct listener *listen, time_t now)
struct sockaddr_in addr, peer;
struct msghdr msg;
struct iovec iov;
int is_err = 1, if_index = 0;
struct ifreq ifr;
int is_err = 1, if_index = 0, mtu = 0;
struct iname *tmp;
struct tftp_transfer *transfer;
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
int mtu = IP_PMTUDISC_DONT;
int mtuflag = IP_PMTUDISC_DONT;
#endif
union {
@@ -83,7 +84,10 @@ void tftp_request(struct listener *listen, time_t now)
return;
if (daemon->options & OPT_NOWILD)
addr = listen->iface->addr.in;
{
addr = listen->iface->addr.in;
mtu = listen->iface->mtu;
}
else
{
char name[IF_NAMESIZE];
@@ -125,7 +129,10 @@ void tftp_request(struct listener *listen, time_t now)
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, name) == 0))
return;
strncpy(name, ifr.ifr_name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
}
addr.sin_port = htons(port);
@@ -158,7 +165,7 @@ void tftp_request(struct listener *listen, time_t now)
{
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
#endif
!fix_fd(transfer->sockfd))
{
@@ -202,6 +209,9 @@ void tftp_request(struct listener *listen, time_t now)
transfer->blocksize = 1;
if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
/* 32 bytes for IP, UDP and TFTP headers */
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32)
transfer->blocksize = (unsigned)mtu - 32;
transfer->opt_blocksize = 1;
transfer->block = 0;
}
@@ -213,6 +223,10 @@ void tftp_request(struct listener *listen, time_t now)
}
}
/* cope with backslashes from windows boxen. */
while ((p = strchr(filename, '\\')))
*p = '/';
strcpy(daemon->namebuff, "/");
if (daemon->tftp_prefix)
{

View File

@@ -24,6 +24,9 @@
#include <sys/times.h>
#endif
#ifdef LOCALEDIR
#include <idna.h>
#endif
#ifdef HAVE_ARC4RANDOM
void rand_init(void)
@@ -95,48 +98,110 @@ unsigned short rand16(void)
#endif
int legal_char(char c)
static int check_name(char *in)
{
/* check for legal char a-z A-Z 0-9 -
(also / , used for RFC2317 and _ used in windows queries
and space, for DNS-SD stuff) */
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '/' || c == '_' || c == ' ')
return 1;
return 0;
}
int canonicalise(char *s)
{
/* check for legal chars and remove trailing .
/* remove trailing .
also fail empty string and label > 63 chars */
size_t dotgap = 0, l = strlen(s);
size_t dotgap = 0, l = strlen(in);
char c;
int nowhite = 0;
if (l == 0 || l > MAXDNAME) return 0;
if (s[l-1] == '.')
if (in[l-1] == '.')
{
if (l == 1) return 0;
s[l-1] = 0;
in[l-1] = 0;
}
while ((c = *s))
for (; (c = *in); in++)
{
if (c == '.')
dotgap = 0;
else if (!legal_char(c) || (++dotgap > MAXLABEL))
else if (++dotgap > MAXLABEL)
return 0;
else if (isascii(c) && iscntrl(c))
/* iscntrl only gives expected results for ascii */
return 0;
#ifndef LOCALEDIR
else if (!isascii(c))
return 0;
#endif
else if (c != ' ')
nowhite = 1;
s++;
}
return nowhite;
if (!nowhite)
return 0;
return 1;
}
/* Hostnames have a more limited valid charset than domain names
so check for legal char a-z A-Z 0-9 - _
Note that this may receive a FQDN, so only check the first label
for the tighter criteria. */
int legal_hostname(char *name)
{
char c;
if (!check_name(name))
return 0;
for (; (c = *name); name++)
/* check for legal char a-z A-Z 0-9 - _ . */
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_')
continue;
/* end of hostname part */
if (c == '.')
return 1;
return 0;
}
return 1;
}
char *canonicalise(char *in, int *nomem)
{
char *ret = NULL;
#ifdef LOCALEDIR
int rc;
#endif
if (nomem)
*nomem = 0;
if (!check_name(in))
return NULL;
#ifdef LOCALEDIR
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
{
if (ret)
free(ret);
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
{
my_syslog(LOG_ERR, _("failed to allocate memory"));
*nomem = 1;
}
return NULL;
}
#else
if ((ret = whine_malloc(strlen(in)+1)))
strcpy(ret, in);
else if (nomem)
*nomem = 1;
#endif
return ret;
}
unsigned char *do_rfc1035_name(unsigned char *p, char *sval)