3 #include <sys/socket.h>
17 #include "smtp_proc.h"
19 #define NITEMS(x) (sizeof(x) / sizeof(*x))
21 typedef int (*smtp_cb)(char *, int, time_t, char *, char *, uint64_t, uint64_t,
26 RB_HEAD(smtp_requests, smtp_request) smtp_requests;
28 static int smtp_register(char *, char *, char *, smtp_cb);
29 static void smtp_newline(int, short, void *);
30 static void smtp_connect(struct smtp_callback *, int, time_t, uint64_t,
32 static void smtp_handle_filter(struct smtp_callback *, int, time_t, uint64_t,
34 static int smtp_request_cmp(struct smtp_request *, struct smtp_request *);
35 RB_PROTOTYPE_STATIC(smtp_requests, smtp_request, entry, smtp_request_cmp);
40 RB_ENTRY(smtp_request) entry;
43 struct smtp_callback {
47 void (*smtp_parse)(struct smtp_callback *, int, time_t, uint64_t,
50 } smtp_callbacks[] = {
51 {"filter", "connect", "smtp-in", smtp_connect, NULL}
55 static int resolved = 1;
58 smtp_register_filter_connect(enum filter_decision (*cb)(char *, int, time_t,
59 char *, char *, uint64_t, uint64_t, struct smtp_filter_connect *))
61 return smtp_register("filter", "connect", "smtp-in", (smtp_cb) cb);
69 printf("register|ready\n");
73 event_set(&stdinev, STDIN_FILENO, EV_READ | EV_PERSIST, smtp_newline,
75 event_add(&stdinev, NULL);
77 if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
84 smtp_newline(int fd, short event, void *arg)
86 struct event *stdinev = (struct event *)arg;
90 char *start, *end, *type, *direction, *phase, *params;
93 uint64_t reqid, token;
96 while ((linelen = getline(&line, &linesize, stdin)) != -1) {
97 if (line[linelen - 1] != '\n')
98 errx(1, "Invalid line received: missing newline");
99 line[linelen - 1] = '\0';
101 if ((start = strchr(type, '|')) == NULL)
102 errx(1, "Invalid line received: missing version");
104 if ((end = strchr(start, '|')) == NULL)
105 errx(1, "Invalid line received: missing time");
107 if (strcmp(start, "1") != 0)
108 errx(1, "Unsupported protocol received: %s", start);
111 if ((direction = strchr(start, '|')) == NULL)
112 errx(1, "Invalid line received: missing direction");
113 direction++[0] = '\0';
114 tm = (time_t) strtoull(start, &end, 10);
115 if (start[0] == '\0' || end[0] != '\0')
116 errx(1, "Invalid line received: invalid timestamp");
117 if ((phase = strchr(direction, '|')) == NULL)
118 errx(1, "Invalid line receieved: missing phase");
120 if ((start = strchr(phase, '|')) == NULL)
121 errx(1, "Invalid line received: missing reqid");
123 reqid = strtoull(start, &end, 16);
124 if (start[0] == '|' || end[0] != '|')
125 errx(1, "Invalid line received: invalid reqid");
128 token = strtoull(start, &end, 16);
129 if (start[0] == '|' || end[0] != '|')
130 errx(1, "Invalid line received: invalid token");
133 for (i = 0; i < NITEMS(smtp_callbacks); i++) {
134 if (strcmp(type, smtp_callbacks[i].type) == 0 &&
135 strcmp(phase, smtp_callbacks[i].phase) == 0 &&
136 strcmp(direction, smtp_callbacks[i].direction) == 0)
139 if (i == NITEMS(smtp_callbacks)) {
140 errx(1, "Invalid line received: received unregistered "
141 "%s: %s", type, phase);
143 smtp_callbacks[i].smtp_parse(&(smtp_callbacks[i]), version, tm,
144 reqid, token, params);
146 if (feof(stdin) || (ferror(stdin) && errno != EAGAIN))
151 smtp_connect(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
152 uint64_t token, char *params)
154 struct smtp_filter_connect sfconnect;
158 sfconnect.hostname = params;
159 if ((address = strchr(params, '|')) == NULL)
160 errx(1, "Invalid line received: missing address");
163 sfconnect.af = AF_INET;
164 if (strncasecmp(address, "ipv6:", 5) == 0) {
165 sfconnect.af = AF_INET6;
169 ret = inet_pton(sfconnect.af, address, sfconnect.af == AF_INET ?
170 (void *)&(sfconnect.addr) : (void *)&(sfconnect.addr6));
172 errx(1, "Invalid line received: Couldn't parse address");
174 err(1, "Couldn't convert address");
176 smtp_handle_filter(cb, version, tm, reqid, token, (void *)(&sfconnect));
180 smtp_handle_filter(struct smtp_callback *cb, int version, time_t tm,
181 uint64_t reqid, uint64_t token, void *params)
183 enum filter_decision fdes;
186 errx(1, "Handling unexpected second request");
188 fdes = cb->cb(cb->type, version, tm, cb->direction, cb->phase, reqid,
193 smtp_filter_proceed(reqid, token);
196 smtp_filter_reject(reqid, token, 451,
197 "Rejected by filter");
199 case FILTER_DISCONNECT:
200 smtp_filter_disconnect(reqid, token,
201 "Rejected by filter");
204 errx(1, "Not sure what is intended here yet");
210 smtp_filter_proceed(uint64_t reqid, uint64_t token)
213 errx(1, "reqid: %016"PRIx64" token: %016"PRIx64" already "
214 "resolved", reqid, token);
215 printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n", token, reqid);
220 smtp_filter_reject(uint64_t reqid, uint64_t token, int code,
221 const char *reason, ...)
226 errx(1, "reqid: %016"PRIx64" token: %016"PRIx64" already "
227 "resolved", reqid, token);
228 if (code < 200 || code > 599)
229 errx(1, "Invalid reject code");
231 printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%d ", token,
233 va_start(ap, reason);
241 smtp_filter_disconnect(uint64_t reqid, uint64_t token, const char *reason, ...)
246 errx(1, "reqid: %016"PRIx64" token: %016"PRIx64" already "
247 "resolved", reqid, token);
248 printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|421 ",
250 va_start(ap, reason);
258 smtp_register(char *type, char *phase, char *direction, smtp_cb cb)
263 errx(1, "Can't register when proc is running");
265 for (i = 0; i < NITEMS(smtp_callbacks); i++) {
266 if (strcmp(type, smtp_callbacks[i].type) == 0 &&
267 strcmp(phase, smtp_callbacks[i].phase) == 0 &&
268 strcmp(direction, smtp_callbacks[i].direction) == 0) {
269 if (smtp_callbacks[i].cb != NULL) {
273 smtp_callbacks[i].cb = cb;
274 printf("register|%s|%s|%s\n", type, direction, phase);
283 smtp_request_cmp(struct smtp_request *r1, struct smtp_request *r2)
285 return r1->reqid - r2->reqid;
288 RB_GENERATE_STATIC(smtp_requests, smtp_request, entry, smtp_request_cmp);