diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2009-02-05 20:28:08 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2012-01-05 17:31:14 +0000 |
commit | 73a08a248d45ca4ed6e5454a174d7248fdbeb17d (patch) | |
tree | 180985ed29bf366e2f5fda0536b567f702f78586 /contrib | |
parent | 9009d74652283dbc47e7701664165170615f25b9 (diff) | |
download | dnsmasq-73a08a248d45ca4ed6e5454a174d7248fdbeb17d.tar.gz |
import of dnsmasq-2.47.tar.gzv2.47
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/lease-access/README | 20 | ||||
-rw-r--r-- | contrib/lease-access/lease.access.patch | 578 |
2 files changed, 598 insertions, 0 deletions
diff --git a/contrib/lease-access/README b/contrib/lease-access/README new file mode 100644 index 0000000..fc66bdf --- /dev/null +++ b/contrib/lease-access/README @@ -0,0 +1,20 @@ +Hello, + +For some specific application I needed to deny access to a MAC address +to a lease. For this reason I modified the dhcp-script behavior and is +called with an extra parameter "access" once a dhcp request or discover +is received. In that case if the exit code of the script is zero, +dnsmasq continues normally, and if non-zero the packet is ignored. + +This was not added as a security feature but as a mean to handle +differently some addresses. It is also quite intrusive since it requires +changes in several other subsystems. + +It attach the patch in case someone is interested. + +regards, +Nikos + +nmav@gennetsa.com + + diff --git a/contrib/lease-access/lease.access.patch b/contrib/lease-access/lease.access.patch new file mode 100644 index 0000000..ad76e25 --- /dev/null +++ b/contrib/lease-access/lease.access.patch @@ -0,0 +1,578 @@ +Index: src/dnsmasq.c +=================================================================== +--- src/dnsmasq.c (revision 696) ++++ src/dnsmasq.c (revision 821) +@@ -59,7 +59,6 @@ + static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp); + static void check_dns_listeners(fd_set *set, time_t now); + static void sig_handler(int sig); +-static void async_event(int pipe, time_t now); + static void fatal_event(struct event_desc *ev); + static void poll_resolv(void); + +@@ -275,7 +274,7 @@ + piperead = pipefd[0]; + pipewrite = pipefd[1]; + /* prime the pipe to load stuff first time. */ +- send_event(pipewrite, EVENT_RELOAD, 0); ++ send_event(pipewrite, EVENT_RELOAD, 0, 0); + + err_pipe[1] = -1; + +@@ -340,7 +339,7 @@ + } + else if (getuid() == 0) + { +- send_event(err_pipe[1], EVENT_PIDFILE, errno); ++ send_event(err_pipe[1], EVENT_PIDFILE, errno, 0); + _exit(0); + } + } +@@ -372,7 +371,7 @@ + (setgroups(0, &dummy) == -1 || + setgid(gp->gr_gid) == -1)) + { +- send_event(err_pipe[1], EVENT_GROUP_ERR, errno); ++ send_event(err_pipe[1], EVENT_GROUP_ERR, errno, 0); + _exit(0); + } + +@@ -415,14 +414,14 @@ + + if (bad_capabilities != 0) + { +- send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities); ++ send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, 0); + _exit(0); + } + + /* finally drop root */ + if (setuid(ent_pw->pw_uid) == -1) + { +- send_event(err_pipe[1], EVENT_USER_ERR, errno); ++ send_event(err_pipe[1], EVENT_USER_ERR, errno, 0); + _exit(0); + } + +@@ -434,7 +433,7 @@ + /* lose the setuid and setgid capbilities */ + if (capset(hdr, data) == -1) + { +- send_event(err_pipe[1], EVENT_CAP_ERR, errno); ++ send_event(err_pipe[1], EVENT_CAP_ERR, errno, 0); + _exit(0); + } + #endif +@@ -647,7 +646,7 @@ + } + + if (FD_ISSET(piperead, &rset)) +- async_event(piperead, now); ++ async_event(piperead, now, NULL, 0); + + #ifdef HAVE_LINUX_NETWORK + if (FD_ISSET(daemon->netlinkfd, &rset)) +@@ -674,7 +673,7 @@ + #endif + + if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset)) +- dhcp_packet(now); ++ dhcp_packet(piperead, now); + + #ifndef NO_FORK + if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset)) +@@ -719,17 +718,18 @@ + else + return; + +- send_event(pipewrite, event, 0); ++ send_event(pipewrite, event, 0, 0); + errno = errsave; + } + } + +-void send_event(int fd, int event, int data) ++void send_event(int fd, int event, int data, int priv) + { + struct event_desc ev; + + ev.event = event; + ev.data = data; ++ ev.priv = priv; + + /* error pipe, debug mode. */ + if (fd == -1) +@@ -771,14 +771,17 @@ + die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE); + } + } +- +-static void async_event(int pipe, time_t now) ++ ++/* returns the private data of the event ++ */ ++int async_event(int pipe, time_t now, struct event_desc* event, unsigned int secs) + { + pid_t p; + struct event_desc ev; + int i; + +- if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1)) ++ if (read_timeout(pipe, (unsigned char *)&ev, sizeof(ev), now, secs) > 0) ++ { + switch (ev.event) + { + case EVENT_RELOAD: +@@ -872,6 +875,14 @@ + flush_log(); + exit(EC_GOOD); + } ++ } ++ else ++ return -1; /* timeout */ ++ ++ if (event) ++ memcpy( event, &ev, sizeof(ev)); ++ ++ return 0; + } + + static void poll_resolv() +Index: src/config.h +=================================================================== +--- src/config.h (revision 696) ++++ src/config.h (revision 821) +@@ -51,6 +51,8 @@ + #define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */ + #define LOG_MAX 5 /* log-queue length */ + #define RANDFILE "/dev/urandom" ++#define SCRIPT_TIMEOUT 6 ++#define LEASE_CHECK_TIMEOUT 10 + + /* DBUS interface specifics */ + #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" +Index: src/dnsmasq.h +=================================================================== +--- src/dnsmasq.h (revision 696) ++++ src/dnsmasq.h (revision 821) +@@ -116,6 +116,7 @@ + /* Async event queue */ + struct event_desc { + int event, data; ++ unsigned int priv; + }; + + #define EVENT_RELOAD 1 +@@ -390,6 +391,7 @@ + #define ACTION_OLD_HOSTNAME 2 + #define ACTION_OLD 3 + #define ACTION_ADD 4 ++#define ACTION_ACCESS 5 + + #define DHCP_CHADDR_MAX 16 + +@@ -709,6 +711,7 @@ + char *print_mac(char *buff, unsigned char *mac, int len); + void bump_maxfd(int fd, int *max); + int read_write(int fd, unsigned char *packet, int size, int rw); ++int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs); + + /* log.c */ + void die(char *message, char *arg1, int exit_code); +@@ -748,7 +751,7 @@ + + /* dhcp.c */ + void dhcp_init(void); +-void dhcp_packet(time_t now); ++void dhcp_packet(int piperead, time_t now); + + struct dhcp_context *address_available(struct dhcp_context *context, + struct in_addr addr, +@@ -792,14 +795,16 @@ + void rerun_scripts(void); + + /* rfc2131.c */ +-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, ++size_t dhcp_reply(int pipefd, struct dhcp_context *context, char *iface_name, int int_index, + size_t sz, time_t now, int unicast_dest, int *is_inform); + + /* dnsmasq.c */ + int make_icmp_sock(void); + int icmp_ping(struct in_addr addr); +-void send_event(int fd, int event, int data); ++void send_event(int fd, int event, int data, int priv); + void clear_cache_and_reload(time_t now); ++int wait_for_child(int pipe); ++int async_event(int pipe, time_t now, struct event_desc*, unsigned int timeout); + + /* isc.c */ + #ifdef HAVE_ISC_READER +@@ -832,9 +837,9 @@ + /* helper.c */ + #ifndef NO_FORK + int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd); +-void helper_write(void); ++int helper_write(void); + void queue_script(int action, struct dhcp_lease *lease, +- char *hostname, time_t now); ++ char *hostname, time_t now, unsigned int uid); + int helper_buf_empty(void); + #endif + +Index: src/util.c +=================================================================== +--- src/util.c (revision 696) ++++ src/util.c (revision 821) +@@ -444,3 +444,38 @@ + return 1; + } + ++int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs) ++{ ++ ssize_t n, done; ++ time_t expire; ++ ++ expire = now + secs; ++ ++ for (done = 0; done < size; done += n) ++ { ++ retry: ++ if (secs > 0) alarm(secs); ++ n = read(fd, &packet[done], (size_t)(size - done)); ++ ++ if (n == 0) ++ return 0; ++ else if (n == -1) ++ { ++ if (errno == EINTR) { ++ my_syslog(LOG_INFO, _("read timed out (errno %d)"), errno); ++ return 0; ++ } ++ ++ if (retry_send() || errno == ENOMEM || errno == ENOBUFS || errno == EAGAIN) ++ { ++ if (secs == 0 || (secs > 0 && dnsmasq_time() < expire)) ++ goto retry; ++ } ++ ++ my_syslog(LOG_INFO, _("error in read (timeout %d, errno %d)"), secs, errno); ++ return 0; ++ } ++ } ++ return 1; ++} ++ +Index: src/dhcp.c +=================================================================== +--- src/dhcp.c (revision 696) ++++ src/dhcp.c (revision 821) +@@ -103,7 +103,7 @@ + daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len); + } + +-void dhcp_packet(time_t now) ++void dhcp_packet(int piperead, time_t now) + { + struct dhcp_packet *mess; + struct dhcp_context *context; +@@ -239,7 +239,8 @@ + if (!iface_enumerate(&parm, complete_context, NULL)) + return; + lease_prune(NULL, now); /* lose any expired leases */ +- iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, ++ ++ iov.iov_len = dhcp_reply(piperead, parm.current, ifr.ifr_name, iface_index, (size_t)sz, + now, unicast_dest, &is_inform); + lease_update_file(now); + lease_update_dns(); +Index: src/helper.c +=================================================================== +--- src/helper.c (revision 696) ++++ src/helper.c (revision 821) +@@ -45,6 +45,7 @@ + #endif + unsigned char hwaddr[DHCP_CHADDR_MAX]; + char interface[IF_NAMESIZE]; ++ unsigned int uid; + }; + + static struct script_data *buf = NULL; +@@ -60,7 +61,7 @@ + then fork our process. */ + if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1) + { +- send_event(err_fd, EVENT_PIPE_ERR, errno); ++ send_event(err_fd, EVENT_PIPE_ERR, errno, 0); + _exit(0); + } + +@@ -87,13 +88,13 @@ + { + if (daemon->options & OPT_NO_FORK) + /* send error to daemon process if no-fork */ +- send_event(event_fd, EVENT_HUSER_ERR, errno); ++ send_event(event_fd, EVENT_HUSER_ERR, errno, 0); + else + { + /* kill daemon */ +- send_event(event_fd, EVENT_DIE, 0); ++ send_event(event_fd, EVENT_DIE, 0, 0); + /* return error */ +- send_event(err_fd, EVENT_HUSER_ERR, errno);; ++ send_event(err_fd, EVENT_HUSER_ERR, errno, 0); + } + _exit(0); + } +@@ -122,6 +123,8 @@ + action_str = "del"; + else if (data.action == ACTION_ADD) + action_str = "add"; ++ else if (data.action == ACTION_ACCESS) ++ action_str = "access"; + else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME) + action_str = "old"; + else +@@ -178,9 +181,11 @@ + { + /* On error send event back to main process for logging */ + if (WIFSIGNALED(status)) +- send_event(event_fd, EVENT_KILLED, WTERMSIG(status)); +- else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) +- send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status)); ++ send_event(event_fd, EVENT_KILLED, WTERMSIG(status), data.uid); ++ else if (WIFEXITED(status)) ++ send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), data.uid); ++ else ++ send_event(event_fd, EVENT_EXITED, -1, data.uid); + break; + } + +@@ -263,7 +268,7 @@ + err = errno; + } + /* failed, send event so the main process logs the problem */ +- send_event(event_fd, EVENT_EXEC_ERR, err); ++ send_event(event_fd, EVENT_EXEC_ERR, err, data.uid); + _exit(0); + } + } +@@ -295,7 +300,7 @@ + } + + /* pack up lease data into a buffer */ +-void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now) ++void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now, unsigned int uid) + { + unsigned char *p; + size_t size; +@@ -332,6 +337,7 @@ + buf_size = size; + } + ++ buf->uid = uid; + buf->action = action; + buf->hwaddr_len = lease->hwaddr_len; + buf->hwaddr_type = lease->hwaddr_type; +@@ -393,12 +399,15 @@ + return bytes_in_buf == 0; + } + +-void helper_write(void) ++/* returns -1 if write failed for a reason, 1 if no data exist ++ * and 0 if everything was ok. ++ */ ++int helper_write(void) + { + ssize_t rc; + + if (bytes_in_buf == 0) +- return; ++ return 1; + + if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1) + { +@@ -409,9 +418,11 @@ + else + { + if (errno == EAGAIN || errno == EINTR) +- return; ++ return -1; + bytes_in_buf = 0; + } ++ ++ return 0; + } + + #endif +Index: src/rfc2131.c +=================================================================== +--- src/rfc2131.c (revision 696) ++++ src/rfc2131.c (revision 821) +@@ -100,8 +100,49 @@ + int clid_len, unsigned char *clid, int *len_out); + static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); + ++static int check_access_script( int piperead, struct dhcp_lease *lease, struct dhcp_packet *mess, time_t now) ++{ ++#ifndef NO_FORK ++unsigned int uid; ++struct event_desc ev; ++int ret; ++struct dhcp_lease _lease; ++ ++ if (daemon->lease_change_command == NULL) return 0; /* ok */ ++ ++ if (!lease) { /* if host has not been seen before lease is NULL */ ++ memset(&_lease, 0, sizeof(_lease)); ++ lease = &_lease; ++ lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0); ++ } ++ ++ uid = rand16(); ++ queue_script(ACTION_ACCESS, lease, NULL, now, uid); ++ ++ /* send all data to helper process */ ++ do ++ { ++ helper_write(); ++ } while (helper_buf_empty() == 0); ++ ++ /* wait for our event */ ++ ret = 0; ++ do ++ { ++ ret = async_event( piperead, now, &ev, SCRIPT_TIMEOUT); ++ } ++ while(ev.priv != uid && ret >= 0); ++ ++ if (ret < 0 || ev.data != 0) /* timeout or error */ ++ { ++ return -1; ++ } ++ ++#endif ++ return 0; /* ok */ ++} + +-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, ++size_t dhcp_reply(int piperead, struct dhcp_context *context, char *iface_name, int int_index, + size_t sz, time_t now, int unicast_dest, int *is_inform) + { + unsigned char *opt, *clid = NULL; +@@ -252,7 +293,7 @@ + mac->netid.next = netid; + netid = &mac->netid; + } +- ++ + /* Determine network for this packet. Our caller will have already linked all the + contexts which match the addresses of the receiving interface but if the + machine has an address already, or came via a relay, or we have a subnet selector, +@@ -329,7 +370,7 @@ + my_syslog(LOG_INFO, _("Available DHCP range: %s -- %s"), daemon->namebuff, inet_ntoa(context_tmp->end)); + } + } +- ++ + mess->op = BOOTREPLY; + + config = find_config(daemon->dhcp_conf, context, clid, clid_len, +@@ -418,7 +459,7 @@ + else + mess->yiaddr = lease->addr; + } +- ++ + if (!message && + !lease && + (!(lease = lease_allocate(mess->yiaddr)))) +@@ -641,7 +682,14 @@ + memcpy(req_options, option_ptr(opt, 0), option_len(opt)); + req_options[option_len(opt)] = OPTION_END; + } +- ++ ++ if (mess_type == DHCPREQUEST || mess_type == DHCPDISCOVER) ++ if (check_access_script(piperead, lease, mess, now) < 0) ++ { ++ my_syslog(LOG_INFO, _("Ignoring client due to access script")); ++ return 0; ++ } ++ + switch (mess_type) + { + case DHCPDECLINE: +Index: src/log.c +=================================================================== +--- src/log.c (revision 696) ++++ src/log.c (revision 821) +@@ -73,7 +73,7 @@ + + if (!log_reopen(daemon->log_file)) + { +- send_event(errfd, EVENT_LOG_ERR, errno); ++ send_event(errfd, EVENT_LOG_ERR, errno, 0); + _exit(0); + } + +Index: src/lease.c +=================================================================== +--- src/lease.c (revision 696) ++++ src/lease.c (revision 821) +@@ -511,7 +511,7 @@ + if (lease->old_hostname) + { + #ifndef NO_FORK +- queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now); ++ queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0); + #endif + free(lease->old_hostname); + lease->old_hostname = NULL; +@@ -520,7 +520,7 @@ + else + { + #ifndef NO_FORK +- queue_script(ACTION_DEL, lease, lease->hostname, now); ++ queue_script(ACTION_DEL, lease, lease->hostname, now, 0); + #endif + old_leases = lease->next; + +@@ -540,7 +540,7 @@ + if (lease->old_hostname) + { + #ifndef NO_FORK +- queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now); ++ queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0); + #endif + free(lease->old_hostname); + lease->old_hostname = NULL; +@@ -552,7 +552,7 @@ + (lease->aux_changed && (daemon->options & OPT_LEASE_RO))) + { + #ifndef NO_FORK +- queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now); ++ queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now, 0); + #endif + lease->new = lease->changed = lease->aux_changed = 0; + +Index: man/dnsmasq.8 +=================================================================== +--- man/dnsmasq.8 (revision 696) ++++ man/dnsmasq.8 (revision 821) +@@ -724,12 +724,15 @@ + .B \-6 --dhcp-script=<path> + Whenever a new DHCP lease is created, or an old one destroyed, the + binary specified by this option is run. The arguments to the process +-are "add", "old" or "del", the MAC ++are "add", "old", "access" or "del", the MAC + address of the host (or "<null>"), the IP address, and the hostname, + if known. "add" means a lease has been created, "del" means it has + been destroyed, "old" is a notification of an existing lease when + dnsmasq starts or a change to MAC address or hostname of an existing + lease (also, lease length or expiry and client-id, if leasefile-ro is set). ++The "access" keyword means that a request was just received and depending ++on the script exit status request for address will be granted, if exit status ++is zero or not if it is non-zero. + The process is run as root (assuming that dnsmasq was originally run as + root) even if dnsmasq is configured to change UID to an unprivileged user. + The environment is inherited from the invoker of dnsmasq, and if the |