import of dnsmasq-2.42.tar.gz

This commit is contained in:
Simon Kelley
2008-05-30 20:06:34 +01:00
parent 824af85bdf
commit 9e038946a1
28 changed files with 3231 additions and 2833 deletions

View File

@@ -69,7 +69,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
#ifdef HAVE_SOCKADDR_SA_LEN
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#else
len = sizeof(struct ifreq);
#endif
@@ -212,8 +212,8 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
sum = (sum & 0xffff) + (sum >> 16);
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
udp.uh_sport = htons(DHCP_SERVER_PORT);
udp.uh_dport = htons(DHCP_CLIENT_PORT);
udp.uh_sport = htons(daemon->dhcp_server_port);
udp.uh_dport = htons(daemon->dhcp_client_port);
if (len & 1)
((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
udp.uh_sum = 0;

View File

@@ -359,6 +359,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
struct crec *new;
union bigname *big_name = NULL;
int freed_all = flags & F_REVERSE;
int free_avail = 0;
log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
@@ -392,8 +393,24 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
if (new->flags & (F_FORWARD | F_REVERSE))
{
/* If free_avail set, we believe that an entry has been freed.
Bugs have been known to make this not true, resulting in
a tight loop here. If that happens, log a warning and abandon the
insert. Once in this state, all inserts will probably fail. */
if (free_avail)
{
static int warned = 0;
if (!warned)
my_syslog(LOG_ERR, "BUG in cache detected. Please mail simon@thekelleys.org.uk");
warned = insert_error = 1;
return NULL;
}
if (freed_all)
{
free_avail = 1; /* Must be free space now. */
cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
cache_live_freed++;
}
@@ -516,19 +533,22 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
Make sure that re-ordering doesn't break the hash-chain
order invariants.
*/
if (!insert)
{
insert = up;
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
up = &crecp->hash_next;
}
else if ((crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
{
*up = crecp->hash_next;
crecp->hash_next = *insert;
*insert = crecp;
insert = &crecp->hash_next;
}
else
{
if (!insert)
{
insert = up;
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
}
up = &crecp->hash_next;
}
}
else
/* case : not expired, incorrect entry. */

View File

@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.41"
#define VERSION "2.42"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -54,6 +54,8 @@
#define CHGRP "dip"
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_ALTPORT 1067
#define DHCP_CLIENT_ALTPORT 1068
#define TFTP_PORT 69
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
@@ -85,13 +87,6 @@
#endif
/* Get linux C library versions. */
#if defined(__linux__) && !defined(__UCLIBC__) && !defined(__uClinux__)
/*# include <libio.h> */
# include <features.h>
#endif
/* Follows system specific switches. If you run on a
new system, you may want to edit these.
May replace this with Autoconf one day.
@@ -153,6 +148,10 @@ HAVE_DBUS
define some methods to allow (re)configuration of the upstream DNS
servers via DBus.
HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
NOTES:
For Linux you should define
HAVE_LINUX_NETWORK
@@ -188,7 +187,7 @@ NOTES:
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* Allow TFTP to be disabled with COPT=-DNO_TFTP */
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP
#undef HAVE_TFTP
#endif
@@ -249,7 +248,10 @@ typedef unsigned long in_addr_t;
# define HAVE_BROKEN_SOCKADDR_IN6
#endif
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#elif defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__DragonFly__) || \
defined (__FreeBSD_kernel__)
#define HAVE_BSD_NETWORK
/* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
@@ -261,6 +263,7 @@ typedef unsigned long in_addr_t;
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__APPLE__)
#define HAVE_BSD_NETWORK
@@ -282,6 +285,7 @@ typedef unsigned long in_addr_t;
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK

View File

@@ -118,7 +118,7 @@ static void dbus_read_servers(DBusMessage *message)
{
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(stuct sockaddr_in6);
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(NAMESERVER_PORT);
@@ -167,8 +167,11 @@ static void dbus_read_servers(DBusMessage *message)
if (!serv && (serv = whine_malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
memset(serv, 0, sizeof(struct server));
if (domain)
serv->domain = whine_malloc(strlen(domain)+1);
if (domain && !serv->domain)
{
free(serv);
@@ -179,7 +182,6 @@ static void dbus_read_servers(DBusMessage *message)
serv->next = daemon->servers;
daemon->servers = serv;
serv->flags = SERV_FROM_DBUS;
serv->sfd = NULL;
if (domain)
{
strcpy(serv->domain, domain);

View File

@@ -71,7 +71,7 @@ void dhcp_init(void)
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(DHCP_SERVER_PORT);
saddr.sin_port = htons(daemon->dhcp_server_port);
saddr.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin_len = sizeof(struct sockaddr_in);
@@ -264,7 +264,7 @@ void dhcp_packet(time_t now)
if (mess->giaddr.s_addr)
{
/* Send to BOOTP relay */
dest.sin_port = htons(DHCP_SERVER_PORT);
dest.sin_port = htons(daemon->dhcp_server_port);
dest.sin_addr = mess->giaddr;
}
else if (mess->ciaddr.s_addr)
@@ -276,7 +276,7 @@ void dhcp_packet(time_t now)
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
{
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
dest.sin_addr = mess->ciaddr;
}
}
@@ -296,7 +296,7 @@ void dhcp_packet(time_t now)
cmptr->cmsg_level = SOL_IP;
cmptr->cmsg_type = IP_PKTINFO;
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
}
else
{
@@ -304,7 +304,7 @@ void dhcp_packet(time_t now)
struct sockaddr limits size to 14 bytes. */
struct arpreq req;
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
*((struct sockaddr_in *)&req.arp_pa) = dest;
req.arp_ha.sa_family = mess->htype;
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
@@ -317,7 +317,7 @@ void dhcp_packet(time_t now)
{
/* broadcast to 255.255.255.255 (or mac address invalid) */
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
/* note that we don't specify the interface here: that's done by the
IP_XMIT_IF sockopt lower down. */
}
@@ -329,7 +329,7 @@ void dhcp_packet(time_t now)
mysteriously. Bah. Fall back to broadcast for other net types. */
struct arpreq req;
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
*((struct sockaddr_in *)&req.arp_pa) = dest;
req.arp_ha.sa_family = AF_UNSPEC;
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);

View File

@@ -33,6 +33,9 @@ static char *compile_opts =
#ifdef NO_FORK
"no-MMU "
#endif
#ifdef HAVE_BSD_BRIDGE
"BSD-bridge "
#endif
#ifndef HAVE_ISC_READER
"no-"
#endif
@@ -216,6 +219,9 @@ int main (int argc, char **argv)
/* The following code "daemonizes" the process.
See Stevens section 12.4 */
if (chdir("/") != 0)
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
#ifndef NO_FORK
if (!(daemon->options & OPT_NO_FORK))
{
@@ -223,7 +229,9 @@ int main (int argc, char **argv)
if ((pid = fork()) == -1 )
die(_("cannot fork into background: %s"), NULL, EC_MISC);
/* NO calls to die() from here on. */
if (pid != 0)
_exit(EC_GOOD);
@@ -234,10 +242,7 @@ int main (int argc, char **argv)
_exit(0);
}
#endif
if (chdir("/") != 0)
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
/* write pidfile _after_ forking ! */
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
{
@@ -259,8 +264,6 @@ int main (int argc, char **argv)
#endif
ent_pw = daemon->username ? getpwnam(daemon->username) : NULL;
/* before here, we should only call die(), after here, only call syslog() */
log_start(ent_pw);
if (!(daemon->options & OPT_DEBUG))
@@ -287,9 +290,20 @@ int main (int argc, char **argv)
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
CAP_NET_RAW (for icmp) if we're doing dhcp */
cap_user_header_t hdr = safe_malloc(sizeof(*hdr));
cap_user_data_t data = safe_malloc(sizeof(*data));
hdr->version = _LINUX_CAPABILITY_VERSION;
cap_user_data_t data;
int capsize = 1; /* for header version 1 */
hdr->version = 0;
/* find version supported by kernel */
capget(hdr, NULL);
if (hdr->version != LINUX_CAPABILITY_VERSION_1)
{
/* if not version 1, use version 2 */
hdr->version = LINUX_CAPABILITY_VERSION_2;
capsize = 2;
}
hdr->pid = 0; /* this process */
data = safe_malloc(sizeof(*data) * capsize);
memset(hdr, sizeof(*data) * capsize, 0);
data->effective = data->permitted = data->inheritable =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
(1 << CAP_SETGID) | (1 << CAP_SETUID);
@@ -688,13 +702,21 @@ static void async_event(int pipe, time_t now)
break;
case EVENT_EXEC_ERR:
my_syslog(LOG_ERR, _("failed to execute %s: %s"), daemon->lease_change_command, strerror(ev.data));
my_syslog(LOG_ERR, _("failed to execute %s: %s"),
daemon->lease_change_command, strerror(ev.data));
break;
case EVENT_PIPE_ERR:
my_syslog(LOG_ERR, _("failed to create helper: %s"), strerror(ev.data));
break;
case EVENT_USER_ERR:
my_syslog(LOG_ERR, _("cannot change to user %s for script execution%s%s"),
daemon->scriptuser,
ev.data != 0 ? ": " : "",
ev.data != 0 ? strerror(ev.data) : "");
break;
case EVENT_REOPEN:
/* Note: this may leave TCP-handling processes with the old file still open.
Since any such process will die in CHILD_LIFETIME or probably much sooner,

View File

@@ -16,6 +16,16 @@
#define COPYRIGHT "Copyright (C) 2000-2008 Simon Kelley"
/* Ensure we can use files >2GB (log files may grow this big) */
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
/* Get linux C library versions. */
#ifdef __linux__
# define _GNU_SOURCE
# include <features.h>
#endif
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
#include <netinet/in.h>
@@ -60,6 +70,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <stddef.h>
#include <time.h>
#include <errno.h>
#include <pwd.h>
@@ -84,8 +95,12 @@
#if defined(HAVE_LINUX_NETWORK)
#include <linux/capability.h>
/* There doesn't seem to be a universally-available
userpace header for this. */
userpace header for these. */
extern int capset(cap_user_header_t header, cap_user_data_t data);
extern int capget(cap_user_header_t header, cap_user_data_t data);
#define LINUX_CAPABILITY_VERSION_1 0x19980330
#define LINUX_CAPABILITY_VERSION_2 0x20071026
#include <sys/prctl.h>
#elif defined(HAVE_SOLARIS_PRIVS)
#include <priv.h>
@@ -109,6 +124,7 @@ struct event_desc {
#define EVENT_KILLED 8
#define EVENT_EXEC_ERR 9
#define EVENT_PIPE_ERR 10
#define EVENT_USER_ERR 11
/* Exit codes. */
#define EC_GOOD 0
@@ -455,7 +471,7 @@ struct dhcp_mac {
struct dhcp_mac *next;
};
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge {
char iface[IF_NAMESIZE];
struct dhcp_bridge *alias, *next;
@@ -509,9 +525,10 @@ struct tftp_transfer {
int sockfd;
time_t timeout;
int backoff;
unsigned int block, blocksize;
unsigned int block, blocksize, expansion;
off_t offset;
struct sockaddr_in peer;
char opt_blocksize, opt_transize;
char opt_blocksize, opt_transize, netascii, carrylf;
struct tftp_file *file;
struct tftp_transfer *next;
};
@@ -529,7 +546,7 @@ extern struct daemon {
struct interface_name *int_names;
char *mxtarget;
char *lease_file;
char *username, *groupname;
char *username, *groupname, *scriptuser;
char *domain_suffix;
char *runfile;
char *lease_change_command;
@@ -552,6 +569,7 @@ extern struct daemon {
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast;
char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port;
int start_tftp_port, end_tftp_port;
unsigned int min_leasetime;
struct doctor *doctors;
@@ -582,7 +600,7 @@ extern struct daemon {
char *dhcp_buff, *dhcp_buff2;
struct ping_result *ping_results;
FILE *lease_stream;
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge *bridges;
#endif

View File

@@ -55,10 +55,18 @@ int create_helper(int event_fd, long max_fd)
pid_t pid;
int i, pipefd[2];
struct sigaction sigact;
struct passwd *ent_pw = NULL;
if (!daemon->dhcp || !daemon->lease_change_command)
return -1;
if (daemon->scriptuser && !(ent_pw = getpwnam(daemon->scriptuser)))
{
/* too late to die() */
send_event(event_fd, EVENT_USER_ERR, 0);
return -1;
}
/* create the pipe through which the main program sends us commands,
then fork our process. By now it's too late to die(), we just log
any failure via the main process. */
@@ -173,6 +181,20 @@ int create_helper(int event_fd, long max_fd)
continue;
}
/* Change ownership of child, if this fails, log and ditch,
rather than running wrong user */
if (ent_pw)
{
gid_t dummy;
if (setgroups(0, &dummy) == -1 ||
setgid(ent_pw->pw_gid) == -1 ||
setuid(ent_pw->pw_uid) == -1)
{
send_event(event_fd, EVENT_USER_ERR, errno);
_exit(0);
}
}
if (data.clid_len != 0)
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);

View File

@@ -27,8 +27,8 @@ int iface_check(int family, struct all_addr *addr,
if (indexp)
{
#if defined(__FreeBSD__) || defined(__DragonFly__)
/* One form of bridging on FreeBSD has the property that packets
#ifdef HAVE_BSD_BRIDGE
/* One form of bridging on BSD has the property that packets
can be recieved on bridge interfaces which do not have an IP address.
We allow these to be treated as aliases of another interface which does have
an IP address with --dhcp-bridge=interface,alias,alias */

View File

@@ -91,6 +91,8 @@ struct myoption {
#define LOPT_MATCH 281
#define LOPT_BROADCAST 282
#define LOPT_NEGTTL 283
#define LOPT_ALTPORT 284
#define LOPT_SCRIPTUSR 285
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -171,7 +173,7 @@ static const struct myoption opts[] =
{"tftp-root", 1, 0, LOPT_PREFIX },
{"tftp-max", 1, 0, LOPT_TFTP_MAX },
{"ptr-record", 1, 0, LOPT_PTR },
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
{"bridge-interface", 1, 0 , LOPT_BRIDGE },
#endif
{"dhcp-option-force", 1, 0, LOPT_FORCE },
@@ -191,6 +193,8 @@ static const struct myoption opts[] =
{"dhcp-match", 1, 0, LOPT_MATCH },
{"dhcp-broadcast", 1, 0, LOPT_BROADCAST },
{"neg-ttl", 1, 0, LOPT_NEGTTL },
{"dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
{"dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
{ NULL, 0, 0, 0 }
};
@@ -308,7 +312,7 @@ static const struct {
{ "-2, --no-dhcp-interface=interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ "-3, --bootp-dynamic", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ "-4, --dhcp-mac=<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
{ " --bridge-interface=iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
#endif
{ "-5, --no-ping", gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
@@ -332,6 +336,8 @@ static const struct {
{ " --stop-dns-rebind", gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
{ " --all-servers", gettext_noop("Always perform DNS queries to all servers."), NULL },
{ " --dhcp-match=<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL },
{ " --dhcp-alternate-port[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ " --dhcp-scriptuser=<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ NULL, NULL, NULL }
};
@@ -396,8 +402,8 @@ static const struct {
{ "client-id", 61,OT_INTERNAL },
{ "nis-domain", 64, 0 },
{ "nis-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, OT_INTERNAL },
{ "bootfile-name", 67, OT_INTERNAL },
{ "tftp-server", 66, 0 },
{ "bootfile-name", 67, 0 },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
{ "smtp-server", 69, OT_ADDR_LIST },
{ "pop3-server", 70, OT_ADDR_LIST },
@@ -1108,6 +1114,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'g': /* --group */
daemon->groupname = opt_string_alloc(arg);
break;
case LOPT_SCRIPTUSR: /* --scriptuser */
daemon->scriptuser = opt_string_alloc(arg);
break;
case 'i': /* --interface */
do {
@@ -1435,7 +1445,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
case LOPT_BRIDGE: /* --bridge-interface */
{
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
@@ -1876,6 +1886,23 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
case LOPT_ALTPORT: /* --dhcp-alternate-port */
if (!arg)
{
daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
}
else
{
comma = split(arg);
if (!atoi_check(arg, &daemon->dhcp_server_port) ||
(comma && !atoi_check(comma, &daemon->dhcp_client_port)))
problem = _("invalid port number");
if (!comma)
daemon->dhcp_client_port = daemon->dhcp_server_port+1;
}
break;
case 'J': /* --dhcp-ignore */
case LOPT_NO_NAMES: /* --dhcp-ignore-names */
case LOPT_BROADCAST: /* --dhcp-broadcast */
@@ -2351,6 +2378,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->cachesize = CACHESIZ;
daemon->ftabsize = FTABSIZ;
daemon->port = NAMESERVER_PORT;
daemon->dhcp_client_port = DHCP_CLIENT_PORT;
daemon->dhcp_server_port = DHCP_SERVER_PORT;
daemon->default_resolv.is_default = 1;
daemon->default_resolv.name = RESOLVFILE;
daemon->resolv_files = &daemon->default_resolv;

View File

@@ -227,7 +227,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
if (*name == '\\' && *(name+1) == '[' &&
(*(name+2) == 'x' || *(name+2) == 'X'))
{
for (j = 0, cp1 = name+3; *cp1 && isxdigit(*cp1) && j < 32; cp1++, j++)
for (j = 0, cp1 = name+3; *cp1 && isxdigit((int) *cp1) && j < 32; cp1++, j++)
{
char xdig[2];
xdig[0] = *cp1;

View File

@@ -82,7 +82,8 @@ static void log_packet(char *type, void *addr,
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id);
static void restore_agent_id(unsigned char *agent_id, struct dhcp_packet *mess, unsigned char *real_end);
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
@@ -436,7 +437,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_expires(lease, 0xffffffff, now); /* infinite lease */
lease_set_interface(lease, int_index);
clear_packet(mess, end);
clear_packet(mess, end, NULL);
do_options(context, mess, end, NULL,
hostname, netid, subnet_addr, 0, 0, NULL);
}
@@ -750,7 +751,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
clear_packet(mess, end);
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
@@ -889,11 +890,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_packet("NAK", &mess->yiaddr, emac, emac_len, iface_name, message);
mess->yiaddr.s_addr = 0;
clear_packet(mess, end);
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ,
ntohl(context ? context->local.s_addr : fallback.s_addr));
option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
/* DHCPNAK gets agent-id too */
restore_agent_id(agent_id, mess, end);
/* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
a distant subnet which unicast a REQ to us won't work. */
if (!unicast_dest || mess->giaddr.s_addr != 0 ||
@@ -970,7 +973,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_packet("ACK", &mess->yiaddr, emac, emac_len, iface_name, hostname);
clear_packet(mess, end);
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
@@ -1015,7 +1018,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &context->netid;
}
clear_packet(mess, end);
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
@@ -1462,14 +1465,29 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
}
}
static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id)
{
/* don't clear agent_id */
if (agent_id)
end = agent_id;
memset(mess->sname, 0, sizeof(mess->sname));
memset(mess->file, 0, sizeof(mess->file));
memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
mess->siaddr.s_addr = 0;
}
static void restore_agent_id(unsigned char *agent_id, struct dhcp_packet *mess, unsigned char *real_end)
{
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 */
}
}
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
@@ -1784,13 +1802,7 @@ static void do_options(struct dhcp_context *context,
}
/* move agent_id back down to the end of the packet */
if (agent_id)
{
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 */
}
restore_agent_id(agent_id, mess, real_end);
/* restore BOOTP anti-overload hack */
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))

View File

@@ -151,8 +151,10 @@ void tftp_request(struct listener *listen, time_t now)
transfer->backoff = 1;
transfer->block = 1;
transfer->blocksize = 512;
transfer->offset = 0;
transfer->file = NULL;
transfer->opt_blocksize = transfer->opt_transize = 0;
transfer->netascii = transfer->carrylf = 0;
/* if we have a nailed-down range, iterate until we find a free one. */
while (1)
@@ -184,10 +186,13 @@ void tftp_request(struct listener *listen, time_t now)
if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
!(filename = next(&p, end)) ||
!(mode = next(&p, end)) ||
strcasecmp(mode, "octet") != 0)
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
else
{
if (strcasecmp(mode, "netascii") == 0)
transfer->netascii = 1;
while ((opt = next(&p, end)))
{
if (strcasecmp(opt, "blksize") == 0 &&
@@ -203,7 +208,7 @@ void tftp_request(struct listener *listen, time_t now)
transfer->block = 0;
}
if (strcasecmp(opt, "tsize") == 0 && next(&p, end))
if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
{
transfer->opt_transize = 1;
transfer->block = 0;
@@ -378,7 +383,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
/* Got ack, ensure we take the (re)transmit path */
transfer->timeout = now;
transfer->backoff = 0;
transfer->block++;
if (transfer->block++ != 0)
transfer->offset += transfer->blocksize - transfer->expansion;
}
else if (ntohs(mess->op) == OP_ERR)
{
@@ -532,24 +538,52 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
unsigned char data[];
} *mess = (struct datamess *)packet;
off_t offset = transfer->blocksize * (transfer->block - 1);
size_t size = transfer->file->size - offset;
size_t size = transfer->file->size - transfer->offset;
if (offset > transfer->file->size)
if (transfer->offset > transfer->file->size)
return 0; /* finished */
if (size > transfer->blocksize)
size = transfer->blocksize;
lseek(transfer->file->fd, offset, SEEK_SET);
mess->op = htons(OP_DATA);
mess->block = htons((unsigned short)(transfer->block));
if (!read_write(transfer->file->fd, mess->data, size, 1))
if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
!read_write(transfer->file->fd, mess->data, size, 1))
return -1;
else
return size + 4;
transfer->expansion = 0;
/* Map '\n' to CR-LF in netascii mode */
if (transfer->netascii)
{
size_t i;
int newcarrylf;
for (i = 0, newcarrylf = 0; i < size; i++)
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
{
if (size == transfer->blocksize)
{
transfer->expansion++;
if (i == size - 1)
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
}
else
size++; /* room in this block */
/* make space and insert CR */
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
mess->data[i] = '\r';
i++;
}
transfer->carrylf = newcarrylf;
}
return size + 4;
}
}