Blob


1 #include <sys/time.h>
2 #include <sys/socket.h>
4 #include <arpa/inet.h>
5 #include <err.h>
6 #include <errno.h>
7 #include <inttypes.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "smtp_proc.h"
14 #define NITEMS(x) (sizeof(x) / sizeof(*x))
16 typedef int (*smtp_cb)(char *, int, time_t, char *, char *, uint64_t, uint64_t,
17 void *);
19 struct smtp_callback;
21 static int smtp_register(char *, char *, char *, smtp_cb);
22 static void smtp_connect(struct smtp_callback *, int, time_t, uint64_t,
23 uint64_t, char *);
24 static void smtp_data(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
25 char *);
26 static void smtp_data_line(struct smtp_callback *, int, time_t, uint64_t,
27 uint64_t, char *);
28 static void smtp_rset(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
29 char *);
30 static void smtp_quit(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
31 char *);
32 static void smtp_noop(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
33 char *);
34 static void smtp_help(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
35 char *);
36 static void smtp_wiz(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
37 char *);
38 static void smtp_commit(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
39 char *);
40 static void smtp_handle(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
41 void *);
43 struct smtp_callback {
44 char *type;
45 char *phase;
46 char *direction;
47 void (*smtp_parse)(struct smtp_callback *, int, time_t, uint64_t,
48 uint64_t, char *);
49 smtp_cb cb;
50 } smtp_callbacks[] = {
51 {"filter", "connect", "smtp-in", smtp_connect, NULL},
52 {"filter", "data", "smtp-in", smtp_data, NULL},
53 {"filter", "data-line", "smtp-in", smtp_data_line, NULL},
54 {"filter", "rset", "smtp-in", smtp_rset, NULL},
55 {"filter", "quit", "smtp-in", smtp_quit, NULL},
56 {"filter", "noop", "smtp-in", smtp_noop, NULL},
57 {"filter", "help", "smtp-in", smtp_help, NULL},
58 {"filter", "wiz", "smtp-in", smtp_wiz, NULL},
59 {"filter", "commit", "smtp-in", smtp_commit, NULL}
60 };
62 static int ready = 0;
64 int
65 smtp_register_filter_connect(enum filter_decision (*cb)(char *, int, time_t,
66 char *, char *, uint64_t, uint64_t, struct smtp_filter_connect *))
67 {
68 return smtp_register("filter", "connect", "smtp-in", (smtp_cb) cb);
69 }
71 void
72 smtp_run(void)
73 {
74 char *line = NULL;
75 size_t linesize = 0;
76 ssize_t linelen;
77 char *start, *end, *type, *direction, *phase, *params;
78 int version;
79 time_t tm;
80 uint64_t reqid, token;
81 int i;
83 printf("register|ready\n");
84 ready = 1;
86 while ((linelen = getline(&line, &linesize, stdin)) != -1) {
87 if (line[linelen - 1] != '\n')
88 errx(1, "Invalid line received: missing newline");
89 line[linelen - 1] = '\0';
90 type = line;
91 if ((start = strchr(type, '|')) == NULL)
92 errx(1, "Invalid line received: missing version");
93 start++[0] = '\0';
94 if ((end = strchr(start, '|')) == NULL)
95 errx(1, "Invalid line received: missing time");
96 end++[0] = '\0';
97 if (strcmp(start, "1") != 0)
98 errx(1, "Unsupported protocol received: %s", start);
99 version = 1;
100 start = end;
101 if ((direction = strchr(start, '|')) == NULL)
102 errx(1, "Invalid line received: missing direction");
103 direction++[0] = '\0';
104 tm = (time_t) strtoull(start, &end, 10);
105 if (start[0] == '\0' || end[0] != '\0')
106 errx(1, "Invalid line received: invalid timestamp");
107 if ((phase = strchr(direction, '|')) == NULL)
108 errx(1, "Invalid line receieved: missing phase");
109 phase++[0] = '\0';
110 if ((start = strchr(phase, '|')) == NULL)
111 errx(1, "Invalid line received: missing reqid");
112 start++[0] = '\0';
113 reqid = strtoull(start, &end, 16);
114 if (start[0] == '|' || end[0] != '|')
115 errx(1, "Invalid line received: invalid reqid");
116 end++[0] = '\0';
117 start = end;
118 token = strtoull(start, &end, 16);
119 if (start[0] == '|' || end[0] != '|')
120 errx(1, "Invalid line received: invalid token");
121 params = end + 1;
123 for (i = 0; i < NITEMS(smtp_callbacks); i++) {
124 if (strcmp(type, smtp_callbacks[i].type) == 0 &&
125 strcmp(phase, smtp_callbacks[i].phase) == 0 &&
126 strcmp(direction, smtp_callbacks[i].direction) == 0)
127 break;
129 if (i == NITEMS(smtp_callbacks)) {
130 errx(1, "Invalid line received: received unregistered "
131 "%s: %s", type, phase);
133 smtp_callbacks[i].smtp_parse(&(smtp_callbacks[i]), version, tm,
134 reqid, token, params);
138 static void
139 smtp_connect(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
140 uint64_t token, char *params)
142 struct smtp_filter_connect sfconnect;
143 char *address;
144 int ret;
146 sfconnect.hostname = params;
147 if ((address = strchr(params, '|')) == NULL)
148 errx(1, "Invalid line received: missing address");
149 address++[0] = '\0';
151 sfconnect.af = AF_INET;
152 if (strncasecmp(address, "ipv6:", 5) == 0) {
153 sfconnect.af = AF_INET6;
154 address += 5;
157 ret = inet_pton(sfconnect.af, address, sfconnect.af == AF_INET ?
158 (void *)&(sfconnect.addr) : (void *)&(sfconnect.addr6));
159 if (ret == 0)
160 errx(1, "Invalid line received: Couldn't parse address");
161 if (ret == -1)
162 err(1, "Couldn't convert address");
164 smtp_handle(cb, version, tm, reqid, token, (void *)(&sfconnect));
167 static void
168 smtp_data(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
169 uint64_t token, char *params)
173 static void
174 smtp_data_line(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
175 uint64_t token, char *params)
179 static void
180 smtp_rset(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
181 uint64_t token, char *params)
185 static void
186 smtp_quit(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
187 uint64_t token, char *params)
191 static void
192 smtp_noop(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
193 uint64_t token, char *params)
197 static void
198 smtp_help(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
199 uint64_t token, char *params)
203 static void
204 smtp_wiz(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
205 uint64_t token, char *params)
209 static void
210 smtp_commit(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
211 uint64_t token, char *params)
215 static void
216 smtp_handle(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
217 uint64_t token, void *params)
219 int ret;
221 switch (cb->cb(cb->type, version, tm, cb->direction, cb->phase, reqid,
222 token, params)) {
223 case FILTER_PROCEED:
224 printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n",
225 token, reqid);
226 break;
227 case FILTER_REJECT:
228 printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%s\n",
229 token, reqid, "451 Proper message later");
230 break;
231 case FILTER_DISCONNECT:
232 printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|"
233 "%s\n", token, reqid, "421 Proper message later");
234 break;
235 case FILTER_REWRITE:
236 errx(1, "Not sure what is intended here yet");
240 static int
241 smtp_register(char *type, char *phase, char *direction, smtp_cb cb)
243 int i;
245 if (ready) {
246 errx(1, "Can't register when proc is running");
248 for (i = 0; i < NITEMS(smtp_callbacks); i++) {
249 if (strcmp(type, smtp_callbacks[i].type) == 0 &&
250 strcmp(phase, smtp_callbacks[i].phase) == 0 &&
251 strcmp(direction, smtp_callbacks[i].direction) == 0) {
252 if (smtp_callbacks[i].cb != NULL) {
253 errno = EALREADY;
254 return -1;
256 smtp_callbacks[i].cb = cb;
257 printf("register|%s|%s|%s\n", type, direction, phase);
258 return 0;
261 errno = EINVAL;
262 return -1;
266 //filter|1|1553668146|smtp-in|connect|478cc771bf86f378|5161a9ce4540b4d1|<unknown>|100.64.7.2