Changeset e87ab6d in code for dns.c


Ignore:
Timestamp:
Mar 9, 2014, 3:09:45 PM (11 years ago)
Author:
Mike Belopuhov <mike@…>
Branches:
master
Children:
dcbd425
Parents:
718d0c9
Message:

Convert DNS code to use ASR

File:
1 edited

Legend:

Unmodified
Added
Removed
  • dns.c

    r718d0c9 re87ab6d  
    11/*
    22 * Copyright (c) 2014 Mike Belopuhov
    3  * Copyright (c) 2009 Michael Shalayeff
    4  * All rights reserved.
     3 *
     4 * ASR implementation and OpenSMTPD integration are copyright
     5 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
     6 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
     7 * Copyright (c) 2011-2012 Eric Faurot <eric@faurot.net>
    58 *
    69 * Permission to use, copy, modify, and distribute this software for any
     
    1720 */
    1821
    19 #include <sys/param.h>
     22#include <sys/types.h>
    2023#include <sys/socket.h>
    2124#include <sys/time.h>
    2225#include <netinet/in.h>
    23 #include <arpa/inet.h>
    2426#include <errno.h>
     27#include <event.h>
     28#include <resolv.h>
    2529#include <stdlib.h>
    2630#include <string.h>
    27 #include <unistd.h>
    2831#include <syslog.h>
    29 #include <sysexits.h>
    30 #include <login_cap.h>
    31 #include <event.h>
    32 #include <pwd.h>
    33 #include <netdb.h>
     32
     33#include "asr.h"
    3434
    3535#include "icb.h"
    3636#include "icbd.h"
    3737
    38 void dns_dispatch(int, short, void *);
    39 void dns_done(int, short, void *);
    40 
    41 struct icbd_dnsquery {
    42         uint64_t                        sid;
    43         union {
    44                 struct sockaddr_storage req;
    45                 char                    rep[NI_MAXHOST];
    46         } u;
    47 };
    48 
    49 int dns_pipe;
     38struct async_event;
     39struct async_event *
     40                async_run_event(struct async *,
     41                    void (*)(int, struct async_res *, void *), void *);
     42void            dns_done(int, struct async_res *, void *);
    5043
    5144extern int dodns;
    5245
    53 int
    54 dns_init(void)
     46void
     47dns_done(int ev __attribute__((__unused__)), struct async_res *ar, void *arg)
    5548{
    56         static struct event ev;
    57         struct passwd *pw;
    58         int pipes[2];
     49        struct icb_session *is = arg;
    5950
    60         if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipes) == -1) {
    61                 syslog(LOG_ERR, "socketpair: %m");
    62                 exit(EX_OSERR);
    63         }
    64 
    65         switch (fork()) {
    66         case -1:
    67                 syslog(LOG_ERR, "fork: %m");
    68                 exit(EX_OSERR);
    69         case 0:
    70                 break;
    71 
    72         default:
    73                 close(pipes[1]);
    74                 dns_pipe = pipes[0];
    75 
    76                 /* event for the reply */
    77                 event_set(&ev, dns_pipe, EV_READ | EV_PERSIST,
    78                     dns_done, NULL);
    79                 if (event_add(&ev, NULL) < 0) {
    80                         syslog(LOG_ERR, "event_add: %m");
    81                         exit (EX_UNAVAILABLE);
    82                 }
    83                 return (0);
    84         }
    85 
    86         setproctitle("dns resolver");
    87         close(pipes[0]);
    88 
    89         if ((pw = getpwnam(ICBD_USER)) == NULL) {
    90                 syslog(LOG_ERR, "No passwd entry for %s", ICBD_USER);
    91                 exit(EX_NOUSER);
    92         }
    93 
    94         if (chdir("/") < 0) {
    95                 syslog(LOG_ERR, "chdir: %m");
    96                 exit(EX_UNAVAILABLE);
    97         }
    98 
    99         if (setusercontext(NULL, pw, pw->pw_uid,
    100             LOGIN_SETALL & ~LOGIN_SETUSER) < 0)
    101                 exit(EX_NOPERM);
    102 
    103         if (setuid(pw->pw_uid) < 0) {
    104                 syslog(LOG_ERR, "%d: %m", pw->pw_uid);
    105                 exit(EX_NOPERM);
    106         }
    107 
    108         event_init();
    109 
    110         /* event for the request */
    111         event_set(&ev, pipes[1], EV_READ | EV_PERSIST, dns_dispatch, NULL);
    112         if (event_add(&ev, NULL) < 0) {
    113                 syslog(LOG_ERR, "event_add: %m");
    114                 exit (EX_UNAVAILABLE);
    115         }
    116 
    117         return event_dispatch();
     51        if (ar->ar_gai_errno == 0) {
     52                syslog(LOG_DEBUG, "dns resolved %s to %s", is->host,
     53                    is->hostname);
     54                if (strncmp(is->hostname, "localhost",
     55                    sizeof "localhost" - 1) == 0)
     56                        strlcpy(is->host, "unknown", ICB_MAXHOSTLEN);
     57                else if (strlen(is->hostname) < ICB_MAXHOSTLEN)
     58                        strlcpy(is->host, is->hostname, ICB_MAXHOSTLEN);
     59        } else
     60                syslog(LOG_WARNING, "dns resolution failed: %s",
     61                    gai_strerror(ar->ar_gai_errno));
    11862}
    11963
    12064void
    121 dns_dispatch(int fd, short event, void *arg __attribute__((unused)))
     65dns_rresolv(struct icb_session *is, struct sockaddr *sa)
    12266{
    123         char host[NI_MAXHOST];
    124         struct sockaddr *sa;
    125         struct icbd_dnsquery q;
    126         ssize_t res;
    127         int gerr;
    128 
    129         if (event != EV_READ)
    130                 return;
    131 
    132         do
    133                 res = read(fd, &q, sizeof q);
    134         while (res == -1 && errno == EINTR);
    135         if (res == -1 && errno == EAGAIN)
    136                 return;
    137         if (res < (ssize_t)sizeof q) {
    138                 syslog(LOG_ERR, "dns_dispatch read: %m");
    139                 /* disable dns resolver */
    140                 dodns = 0;
    141                 return;
    142         }
    143 
    144         sa = (struct sockaddr *)&q.u.req;
    145         if ((gerr = getnameinfo(sa, sa->sa_len,
    146             host, sizeof host, NULL, 0, NI_NOFQDN))) {
    147                 syslog(LOG_ERR, "getnameinfo: %s", gai_strerror(gerr));
    148                 return;
    149         }
    150 
    151         if (verbose)
    152                 syslog(LOG_DEBUG, "dns_dispatch: resolved %s", host);
    153 
    154         memcpy(&q.u.rep, host, sizeof host);
    155         if (write(fd, &q, sizeof q) != sizeof q)
    156                 syslog(LOG_ERR, "dns_dispatch write: %m");
    157 }
    158 
    159 void
    160 dns_done(int fd, short event, void *arg __attribute__((unused)))
    161 {
    162         struct icb_session *is;
    163         struct icbd_dnsquery q;
    164         ssize_t res;
    165 
    166         if (event != EV_READ)
    167                 return;
    168 
    169         do
    170                 res = read(fd, &q, sizeof q);
    171         while (res == -1 && errno == EINTR);
    172         if (res == -1 && errno == EAGAIN)
    173                 return;
    174         if (res < (ssize_t)sizeof q) {
    175                 syslog(LOG_ERR, "dns_done read: %m");
    176                 return;
    177         }
    178 
    179         if ((is = icbd_session_lookup(q.sid)) == NULL) {
    180                 syslog(LOG_DEBUG, "failed to find session %llu", q.sid);
    181                 return;
    182         }
    183 
    184         if (verbose)
    185                 syslog(LOG_DEBUG, "icbd_dns: resolved %s to %s",
    186                     is->host, q.u.rep);
    187 
    188         /* XXX */
    189         if (strcmp(q.u.rep, "localhost") == 0)
    190                 strlcpy(is->host, "unknown", ICB_MAXHOSTLEN);
    191         else if (strlen(q.u.rep) < ICB_MAXHOSTLEN)
    192                 strlcpy(is->host, q.u.rep, ICB_MAXHOSTLEN);
    193 }
    194 
    195 void
    196 dns_rresolv(struct icb_session *is, struct sockaddr_storage *ss)
    197 {
    198         struct icbd_dnsquery q;
     67        struct async *as;
    19968
    20069        if (!dodns)
     
    20473                syslog(LOG_DEBUG, "resolving: %s", is->host);
    20574
    206         memset(&q, 0, sizeof q);
    207         q.sid = is->id;
    208         memcpy(&q.u.req, ss, sizeof *ss);
    209         if (write(dns_pipe, &q, sizeof q) != sizeof q) {
    210                 syslog(LOG_ERR, "dns_rresolv write: %m");
    211                 exit(EX_OSERR);
     75        as = getnameinfo_async(sa, sa->sa_len, is->hostname,
     76            sizeof is->hostname, NULL, 0, NI_NOFQDN, NULL);
     77        async_run_event(as, dns_done, is);
     78}
     79
     80/* Generic libevent glue for asr */
     81
     82struct async_event {
     83        struct async    *async;
     84        struct event     ev;
     85        void            (*callback)(int, struct async_res *, void *);
     86        void            *arg;
     87};
     88
     89void async_event_dispatch(int, short, void *);
     90
     91struct async_event *
     92async_run_event(struct async * async,
     93    void (*cb)(int, struct async_res *, void *), void *arg)
     94{
     95        struct async_event      *aev;
     96        struct timeval           tv;
     97
     98        aev = calloc(1, sizeof *aev);
     99        if (aev == NULL)
     100                return (NULL);
     101        aev->async = async;
     102        aev->callback = cb;
     103        aev->arg = arg;
     104        tv.tv_sec = 0;
     105        tv.tv_usec = 0;
     106        evtimer_set(&aev->ev, async_event_dispatch, aev);
     107        evtimer_add(&aev->ev, &tv);
     108        return (aev);
     109}
     110
     111void
     112async_event_dispatch(int fd __attribute__((__unused__)),
     113    short ev __attribute__((__unused__)), void *arg)
     114{
     115        struct async_event      *aev = arg;
     116        struct async_res         ar;
     117        int                      r;
     118        struct timeval           tv;
     119
     120        while ((r = asr_async_run(aev->async, &ar)) == ASYNC_YIELD)
     121                aev->callback(r, &ar, aev->arg);
     122
     123        event_del(&aev->ev);
     124        if (r == ASYNC_COND) {
     125                event_set(&aev->ev, ar.ar_fd,
     126                          ar.ar_cond == ASYNC_READ ? EV_READ : EV_WRITE,
     127                          async_event_dispatch, aev);
     128                tv.tv_sec = ar.ar_timeout / 1000;
     129                tv.tv_usec = (ar.ar_timeout % 1000) * 1000;
     130                event_add(&aev->ev, &tv);
     131        } else { /* ASYNC_DONE */
     132                aev->callback(r, &ar, aev->arg);
     133                free(aev);
    212134        }
    213135}
Note: See TracChangeset for help on using the changeset viewer.