Blame


1 a248a3c1 2019-03-27 martijn #include <sys/socket.h>
2 a248a3c1 2019-03-27 martijn
3 a248a3c1 2019-03-27 martijn #include <err.h>
4 a248a3c1 2019-03-27 martijn #include <errno.h>
5 a248a3c1 2019-03-27 martijn #include <netdb.h>
6 a248a3c1 2019-03-27 martijn #include <stdlib.h>
7 a248a3c1 2019-03-27 martijn #include <stdio.h>
8 a248a3c1 2019-03-27 martijn #include <string.h>
9 a248a3c1 2019-03-27 martijn #include <unistd.h>
10 a248a3c1 2019-03-27 martijn
11 a248a3c1 2019-03-27 martijn #include "smtp_proc.h"
12 a248a3c1 2019-03-27 martijn
13 a248a3c1 2019-03-27 martijn static char **blacklists = NULL;
14 a248a3c1 2019-03-27 martijn static size_t nblacklists = 0;
15 a248a3c1 2019-03-27 martijn int retries = 0;
16 57cbfccc 2019-03-27 martijn int reject_onfailure = 0;
17 a248a3c1 2019-03-27 martijn
18 a248a3c1 2019-03-27 martijn void usage(void);
19 a248a3c1 2019-03-27 martijn enum filter_decision dnsbl_connect(char *, int, time_t, char *, char *,
20 a248a3c1 2019-03-27 martijn uint64_t, uint64_t, struct smtp_filter_connect *);
21 a248a3c1 2019-03-27 martijn
22 a248a3c1 2019-03-27 martijn int
23 a248a3c1 2019-03-27 martijn main(int argc, char *argv[])
24 a248a3c1 2019-03-27 martijn {
25 a248a3c1 2019-03-27 martijn int ch;
26 a248a3c1 2019-03-27 martijn size_t i;
27 a248a3c1 2019-03-27 martijn char *line = NULL;
28 a248a3c1 2019-03-27 martijn size_t linesize = 0;
29 a248a3c1 2019-03-27 martijn ssize_t linelen;
30 a248a3c1 2019-03-27 martijn char *msgid, *token, *ip;
31 a248a3c1 2019-03-27 martijn const char *errstr;
32 a248a3c1 2019-03-27 martijn int lookup;
33 a248a3c1 2019-03-27 martijn
34 a248a3c1 2019-03-27 martijn if (pledge("stdio dns", NULL) == -1)
35 a248a3c1 2019-03-27 martijn err(1, "pledge");
36 a248a3c1 2019-03-27 martijn
37 a248a3c1 2019-03-27 martijn while ((ch = getopt(argc, argv, "b:f:r:")) != -1) {
38 a248a3c1 2019-03-27 martijn switch (ch) {
39 a248a3c1 2019-03-27 martijn case 'b':
40 a248a3c1 2019-03-27 martijn blacklists = reallocarray(blacklists, nblacklists + 1,
41 a248a3c1 2019-03-27 martijn sizeof(*blacklists));
42 a248a3c1 2019-03-27 martijn if (blacklists == NULL)
43 a248a3c1 2019-03-27 martijn err(1, NULL);
44 a248a3c1 2019-03-27 martijn if ((blacklists[nblacklists] = strdup(optarg)) == NULL)
45 a248a3c1 2019-03-27 martijn err(1, NULL);
46 a248a3c1 2019-03-27 martijn nblacklists++;
47 a248a3c1 2019-03-27 martijn break;
48 a248a3c1 2019-03-27 martijn case 'f':
49 57cbfccc 2019-03-27 martijn reject_onfailure = 1;
50 a248a3c1 2019-03-27 martijn case 'r':
51 a248a3c1 2019-03-27 martijn if ((retries = strtonum(optarg, 0, 10, &errstr)) == 0 &&
52 a248a3c1 2019-03-27 martijn errstr != NULL)
53 a248a3c1 2019-03-27 martijn errx(1, "retries %s", errstr);
54 a248a3c1 2019-03-27 martijn break;
55 a248a3c1 2019-03-27 martijn default:
56 a248a3c1 2019-03-27 martijn usage();
57 a248a3c1 2019-03-27 martijn }
58 a248a3c1 2019-03-27 martijn }
59 a248a3c1 2019-03-27 martijn
60 a248a3c1 2019-03-27 martijn if (nblacklists == 0)
61 a248a3c1 2019-03-27 martijn errx(1, "No blacklist specified");
62 a248a3c1 2019-03-27 martijn
63 a248a3c1 2019-03-27 martijn smtp_register_filter_connect(dnsbl_connect);
64 a248a3c1 2019-03-27 martijn smtp_run();
65 a248a3c1 2019-03-27 martijn
66 a248a3c1 2019-03-27 martijn return 0;
67 a248a3c1 2019-03-27 martijn }
68 a248a3c1 2019-03-27 martijn
69 a248a3c1 2019-03-27 martijn enum filter_decision
70 a248a3c1 2019-03-27 martijn dnsbl_connect(char *type, int version, time_t tm, char *direction, char *phase,
71 a248a3c1 2019-03-27 martijn uint64_t reqid, uint64_t token, struct smtp_filter_connect *params)
72 a248a3c1 2019-03-27 martijn {
73 a248a3c1 2019-03-27 martijn char query[255];
74 a248a3c1 2019-03-27 martijn char reply[1500];
75 a248a3c1 2019-03-27 martijn struct hostent *hent;
76 a248a3c1 2019-03-27 martijn u_char *addr;
77 57cbfccc 2019-03-27 martijn int i, try;
78 a248a3c1 2019-03-27 martijn
79 a248a3c1 2019-03-27 martijn addr = (u_char *)&(params->addr);
80 a248a3c1 2019-03-27 martijn for (i = 0; i < nblacklists; i++) {
81 a248a3c1 2019-03-27 martijn if (params->af == AF_INET) {
82 a248a3c1 2019-03-27 martijn if (snprintf(query, sizeof(query), "%u.%u.%u.%u.%s",
83 a248a3c1 2019-03-27 martijn addr[3], addr[2], addr[1], addr[0],
84 a248a3c1 2019-03-27 martijn blacklists[i]) >= sizeof(query))
85 a248a3c1 2019-03-27 martijn errx(1, "Can't create query, domain too long");
86 a248a3c1 2019-03-27 martijn } else if (params->af == AF_INET6) {
87 a248a3c1 2019-03-27 martijn if (snprintf(query, sizeof(query), "%hhx.%hhx.%hhx.%hhx"
88 a248a3c1 2019-03-27 martijn ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx"
89 a248a3c1 2019-03-27 martijn ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx"
90 a248a3c1 2019-03-27 martijn ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%s",
91 a248a3c1 2019-03-27 martijn (u_char) (addr[15] & 0xf), (u_char) (addr[15] >> 4),
92 a248a3c1 2019-03-27 martijn (u_char) (addr[14] & 0xf), (u_char) (addr[14] >> 4),
93 a248a3c1 2019-03-27 martijn (u_char) (addr[13] & 0xf), (u_char) (addr[13] >> 4),
94 a248a3c1 2019-03-27 martijn (u_char) (addr[12] & 0xf), (u_char) (addr[12] >> 4),
95 a248a3c1 2019-03-27 martijn (u_char) (addr[11] & 0xf), (u_char) (addr[11] >> 4),
96 a248a3c1 2019-03-27 martijn (u_char) (addr[10] & 0xf), (u_char) (addr[10] >> 4),
97 a248a3c1 2019-03-27 martijn (u_char) (addr[9] & 0xf), (u_char) (addr[9] >> 4),
98 a248a3c1 2019-03-27 martijn (u_char) (addr[8] & 0xf), (u_char) (addr[8] >> 4),
99 a248a3c1 2019-03-27 martijn (u_char) (addr[7] & 0xf), (u_char) (addr[8] >> 4),
100 a248a3c1 2019-03-27 martijn (u_char) (addr[6] & 0xf), (u_char) (addr[7] >> 4),
101 a248a3c1 2019-03-27 martijn (u_char) (addr[5] & 0xf), (u_char) (addr[5] >> 4),
102 a248a3c1 2019-03-27 martijn (u_char) (addr[4] & 0xf), (u_char) (addr[4] >> 4),
103 a248a3c1 2019-03-27 martijn (u_char) (addr[3] & 0xf), (u_char) (addr[3] >> 4),
104 a248a3c1 2019-03-27 martijn (u_char) (addr[2] & 0xf), (u_char) (addr[2] >> 4),
105 a248a3c1 2019-03-27 martijn (u_char) (addr[1] & 0xf), (u_char) (addr[1] >> 4),
106 a248a3c1 2019-03-27 martijn (u_char) (addr[0] & 0xf), (u_char) (addr[0] >> 4),
107 a248a3c1 2019-03-27 martijn blacklists[i]) >= sizeof(query))
108 a248a3c1 2019-03-27 martijn errx(1, "Can't create query, domain too long");
109 a248a3c1 2019-03-27 martijn } else
110 a248a3c1 2019-03-27 martijn errx(1, "Invalid address family received");
111 a248a3c1 2019-03-27 martijn
112 57cbfccc 2019-03-27 martijn for (try = -1; try < retries; try++) {
113 57cbfccc 2019-03-27 martijn if ((hent = gethostbyname(query)) == NULL) {
114 57cbfccc 2019-03-27 martijn if (h_errno == HOST_NOT_FOUND)
115 57cbfccc 2019-03-27 martijn break;
116 57cbfccc 2019-03-27 martijn if (h_errno != TRY_AGAIN) {
117 57cbfccc 2019-03-27 martijn if (!reject_onfailure)
118 57cbfccc 2019-03-27 martijn break;
119 57cbfccc 2019-03-27 martijn else
120 57cbfccc 2019-03-27 martijn smtp_filter_disconnect(reqid,
121 57cbfccc 2019-03-27 martijn token,
122 57cbfccc 2019-03-27 martijn "Blacklist check failed");
123 57cbfccc 2019-03-27 martijn return FILTER_DISCONNECT;
124 57cbfccc 2019-03-27 martijn }
125 57cbfccc 2019-03-27 martijn } else {
126 57cbfccc 2019-03-27 martijn smtp_filter_disconnect(reqid, token,
127 57cbfccc 2019-03-27 martijn "Listed at %s", blacklists[i]);
128 57cbfccc 2019-03-27 martijn return FILTER_DISCONNECT;
129 57cbfccc 2019-03-27 martijn }
130 a248a3c1 2019-03-27 martijn }
131 a248a3c1 2019-03-27 martijn }
132 57cbfccc 2019-03-27 martijn return FILTER_PROCEED;
133 a248a3c1 2019-03-27 martijn }
134 a248a3c1 2019-03-27 martijn
135 a248a3c1 2019-03-27 martijn void
136 a248a3c1 2019-03-27 martijn usage(void)
137 a248a3c1 2019-03-27 martijn {
138 a248a3c1 2019-03-27 martijn fprintf(stderr, "usage: %s [-b blacklist]\n",
139 a248a3c1 2019-03-27 martijn getprogname());
140 a248a3c1 2019-03-27 martijn exit(1);
141 a248a3c1 2019-03-27 martijn }