update the relay dns code to open a new udp socket to send the
authorreyk <reyk@openbsd.org>
Wed, 9 Jul 2008 10:50:34 +0000 (10:50 +0000)
committerreyk <reyk@openbsd.org>
Wed, 9 Jul 2008 10:50:34 +0000 (10:50 +0000)
forwarded dns request to the server instead of sending from the server
socket.  this will fix the limitation the the dns relay had to listen
to the "0.0.0.0" address, and will also enable relayd to use the udp
source port randomization. relayd will know randomize the source port
(on OpenBSD) and DNS request identifier for the clients behind it.

ok pyr@

usr.sbin/relayd/relay_udp.c
usr.sbin/relayd/relayd.h

index f52c041..9108370 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: relay_udp.c,v 1.11 2008/05/08 02:27:58 reyk Exp $     */
+/*     $OpenBSD: relay_udp.c,v 1.12 2008/07/09 10:50:34 reyk Exp $     */
 
 /*
  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -61,10 +61,12 @@ void                 relay_udp_request(struct session *);
 void            relay_udp_timeout(int, short, void *);
 
 void            relay_dns_log(struct session *, u_int8_t *);
-void           *relay_dns_validate(struct relay *, struct sockaddr_storage *,
+void           *relay_dns_validate(struct session *,
+                   struct relay *, struct sockaddr_storage *,
                    u_int8_t *, size_t);
 int             relay_dns_request(struct session *);
-void            relay_dns_response(struct session *, u_int8_t *, size_t);
+void            relay_udp_response(int, short, void *);
+void            relay_dns_result(struct session *, u_int8_t *, size_t);
 int             relay_dns_cmp(struct session *, struct session *);
 
 void
@@ -162,6 +164,37 @@ relay_udp_socket(struct sockaddr_storage *ss, in_port_t port,
        return (-1);
 }
 
+void
+relay_udp_response(int fd, short sig, void *arg)
+{
+       struct session          *con = (struct session *)arg;
+       struct relay            *rlay = con->se_relay;
+       struct protocol         *proto = rlay->rl_proto;
+       struct sockaddr_storage  ss;
+       u_int8_t                 buf[READ_BUF_SIZE];
+       ssize_t                  len;
+       socklen_t                slen;
+
+       if (sig == EV_TIMEOUT) {
+               relay_udp_timeout(fd, sig, arg);
+               return;
+       }
+
+       if (relay_sessions >= RELAY_MAX_SESSIONS ||
+           rlay->rl_conf.flags & F_DISABLE)
+               return;
+
+       slen = sizeof(ss);
+       if ((len = recvfrom(fd, buf, sizeof(buf), 0,
+           (struct sockaddr*)&ss, &slen)) < 1)
+               return;
+
+       /* Parse and validate the packet header */
+       if (proto->validate != NULL &&
+           (*proto->validate)(con, rlay, &ss, buf, len) == NULL)
+               return;
+}
+
 void
 relay_udp_server(int fd, short sig, void *arg)
 {
@@ -185,9 +218,8 @@ relay_udp_server(int fd, short sig, void *arg)
            (struct sockaddr*)&ss, &slen)) < 1)
                return;
 
-       /* Parse and validate the packet header */
        if (proto->validate != NULL &&
-           (priv = (*proto->validate)(rlay, &ss, buf, len)) == NULL)
+           (priv = (*proto->validate)(NULL, rlay, &ss, buf, len)) == NULL)
                return;
 
        if ((con = (struct session *)
@@ -346,11 +378,11 @@ relay_dns_log(struct session *con, u_int8_t *buf)
 }
 
 void *
-relay_dns_validate(struct relay *rlay, struct sockaddr_storage *ss,
-    u_int8_t *buf, size_t len)
+relay_dns_validate(struct session *con, struct relay *rlay,
+    struct sockaddr_storage *ss, u_int8_t *buf, size_t len)
 {
        struct relay_dnshdr     *hdr = (struct relay_dnshdr *)buf;
-       struct session          *con, lookup;
+       struct session           lookup;
        u_int16_t                key;
        struct relay_dns_priv   *priv, lpriv;
 
@@ -377,12 +409,16 @@ relay_dns_validate(struct relay *rlay, struct sockaddr_storage *ss,
         * Lookup if this response is for a known session and if the
         * remote host matches the original destination of the request.
         */
-       lpriv.dp_inkey = key;
-       lookup.se_priv = &lpriv;
-       if ((con = SPLAY_FIND(session_tree,
-           &rlay->rl_sessions, &lookup)) != NULL && con->se_priv != NULL &&
-           relay_cmp_af(ss, &con->se_out.ss) == 0)
-               relay_dns_response(con, buf, len);
+       if (con == NULL) {
+               lpriv.dp_inkey = key;
+               lookup.se_priv = &lpriv;
+               if ((con = SPLAY_FIND(session_tree,
+                   &rlay->rl_sessions, &lookup)) != NULL &&
+                   con->se_priv != NULL &&
+                   relay_cmp_af(ss, &con->se_out.ss) == 0)
+                       relay_dns_result(con, buf, len);
+       } else
+               relay_dns_result(con, buf, len);
 
        /*
         * This is not a new session, ignore it in the UDP server.
@@ -416,7 +452,8 @@ relay_dns_request(struct session *con)
                con->se_out.port = rlay->rl_conf.dstport;
        }
 
-       if (relay_socket_af(&con->se_out.ss, con->se_out.port) == -1)
+       if ((con->se_out.s = relay_udp_socket(&con->se_out.ss,
+           con->se_out.port, rlay->rl_proto)) == -1)
                return (-1);
        slen = con->se_out.ss.ss_len;
 
@@ -424,7 +461,7 @@ relay_dns_request(struct session *con)
        hdr->dns_id = htons(priv->dp_inkey);
 
  retry:
-       if (sendto(rlay->rl_s, buf, len, 0,
+       if (sendto(con->se_out.s, buf, len, 0,
            (struct sockaddr *)&con->se_out.ss, slen) == -1) {
                if (con->se_retry) {
                        con->se_retry--;
@@ -439,14 +476,14 @@ relay_dns_request(struct session *con)
                return (-1);
        }
 
-       event_again(&con->se_ev, con->se_out.s, EV_TIMEOUT,
-           relay_udp_timeout, &con->se_tv_start, &env->sc_timeout, con);
+       event_again(&con->se_ev, con->se_out.s, EV_TIMEOUT|EV_READ,
+           relay_udp_response, &con->se_tv_start, &env->sc_timeout, con);
 
        return (0);
 }
 
 void
-relay_dns_response(struct session *con, u_int8_t *buf, size_t len)
+relay_dns_result(struct session *con, u_int8_t *buf, size_t len)
 {
        struct relay            *rlay = (struct relay *)con->se_relay;
        struct relay_dns_priv   *priv = (struct relay_dns_priv *)con->se_priv;
@@ -454,7 +491,7 @@ relay_dns_response(struct session *con, u_int8_t *buf, size_t len)
        socklen_t                slen;
 
        if (priv == NULL)
-               fatalx("relay_dns_response: response to invalid session");
+               fatalx("relay_dns_result: response to invalid session");
 
        if (debug)
                relay_dns_log(con, buf);
index c30812f..432f460 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: relayd.h,v 1.103 2008/06/11 18:21:20 reyk Exp $       */
+/*     $OpenBSD: relayd.h,v 1.104 2008/07/09 10:50:34 reyk Exp $       */
 
 /*
  * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -558,7 +558,7 @@ struct protocol {
        struct proto_tree        response_tree;
 
        int                     (*cmp)(struct session *, struct session *);
-       void                    *(*validate)(struct relay *,
+       void                    *(*validate)(struct session *, struct relay *,
                                    struct sockaddr_storage *,
                                    u_int8_t *, size_t);
        int                     (*request)(struct session *);