1 /*
2 * AXA protocol utilities
3 *
4 * Copyright (c) 2014-2018 by Farsight Security, Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <axa/axa_endian.h>
20 #include <axa/wire.h>
21
22 #include <nmsg.h>
23 #include <wdns.h>
24
25 #include <arpa/inet.h>
26 #include <arpa/nameser.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <netinet/ip.h>
30 #include <netinet/ip6.h>
31 #define __FAVOR_BSD /* for Debian tcp.h and udp.h */
32 #include <netinet/udp.h>
33 #include <netinet/tcp.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #ifdef __linux
38 #include <bsd/string.h> /* for strlcpy() */
39 #include <time.h> /* for localtime() and strftime() */
40 #endif
41 #include <sys/uio.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44
45
46 /* Point to the value string after "ip=", "dns=", or "ch=".
47 * Allow whitespace around '=' or instead of '='.
48 */
49 static const char *
get_value(const char * arg,const char * type,size_t type_len)50 get_value(const char *arg,
51 const char *type, size_t type_len) /* "ip", "dns", or "ch" */
52 {
53 size_t sep_len;
54
55 if (strncasecmp(arg, type, type_len) != 0)
56 return (NULL);
57 arg += strlen(type);
58 sep_len = strspn(arg, AXA_WHITESPACE);
59 arg += sep_len;
60 if (*arg == '=') {
61 ++arg;
62 arg += strspn(arg, AXA_WHITESPACE);
63 } else if (sep_len == 0) {
64 return (NULL);
65 }
66 return (arg);
67 }
68
69 /*
70 * Parse an AXA watch definition.
71 * false=problem
72 * with emsg->c a relevant error message except when the watch
73 * makes no sense. In that case, emsg->c[0] == '\0'.
74 */
75 bool
axa_parse_watch(axa_emsg_t * emsg,axa_p_watch_t * watch,size_t * watch_len,const char * arg)76 axa_parse_watch(axa_emsg_t *emsg,
77 axa_p_watch_t *watch, /* parsed result */
78 size_t *watch_len,
79 const char *arg) /* null terminated input */
80 {
81 const char *value;
82 int prefix;
83 axa_socku_t su;
84 axa_p_ch_t ch;
85 wdns_name_t name;
86
87 memset(watch, 0, sizeof(*watch));
88 *watch_len = sizeof(*watch) - sizeof(watch->pat);
89
90 if ((value = get_value(arg, "ip", sizeof("ip")-1)) != NULL) {
91 if (*value == '\0') {
92 axa_pemsg(emsg, "missing IP address");
93 return (false);
94 }
95 prefix = axa_str_to_cidr(emsg, &su, value);
96 if (prefix <= 0)
97 return (false);
98 watch->prefix = prefix;
99 if (su.sa.sa_family == AF_INET) {
100 watch->type = AXA_P_WATCH_IPV4;
101 if (watch->prefix < 32)
102 watch->flags |= AXA_P_WATCH_FG_WILD;
103 watch->pat.addr = su.ipv4.sin_addr;
104 /* Be conservative in what we send by not trimming
105 * the address. */
106 *watch_len += sizeof(watch->pat.addr);
107 } else {
108 watch->type = AXA_P_WATCH_IPV6;
109 if (watch->prefix < 128)
110 watch->flags |= AXA_P_WATCH_FG_WILD;
111 watch->pat.addr6 = su.ipv6.sin6_addr;
112 /* Be conservative in what we send by not trimming
113 * the address. */
114 *watch_len += sizeof(watch->pat.addr6);
115 }
116 return (true);
117 }
118
119 if ((value = get_value(arg, "dns", sizeof("dns")-1)) != NULL) {
120 watch->type = AXA_P_WATCH_DNS;
121 if (*value == '*') {
122 watch->flags |= AXA_P_WATCH_FG_WILD;
123 if (*++value == '.' && value[1] != '\0')
124 ++value;
125 }
126 if (*value == '\0') {
127 axa_pemsg(emsg, "missing domain name");
128 return (false);
129 }
130 name.data = NULL;
131 if (wdns_str_to_name(value, &name) != wdns_res_success) {
132 axa_pemsg(emsg, "invalid DNS name \"%s\"", value);
133 return (false);
134 }
135 memcpy(watch->pat.dns, name.data, name.len);
136 *watch_len += name.len;
137 free(name.data);
138 return (true);
139 }
140
141 if ((value = get_value(arg, AXA_OP_CH_PREFIX,
142 sizeof(AXA_OP_CH_PREFIX)-1)) != NULL) {
143 if (*value == '\0') {
144 axa_pemsg(emsg, "missing channel");
145 return (false);
146 }
147 watch->type = AXA_P_WATCH_CH;
148 if (!axa_parse_ch(emsg, &ch,
149 value, strlen(value), false, true))
150 return (false);
151 watch->pat.ch = AXA_H2P_CH(ch);
152 *watch_len += sizeof(watch->pat.ch);
153 return (true);
154 }
155
156 if (AXA_CLITCMP(arg, "errors")) {
157 arg += sizeof("errors")-1;
158 arg += strspn(arg, AXA_WHITESPACE);
159 if (*arg == '\0') {
160 watch->type = AXA_P_WATCH_ERRORS;
161 return (true);
162 }
163 }
164 if (AXA_CLITCMP(arg, "error")) {
165 arg += sizeof("error")-1;
166 arg += strspn(arg, AXA_WHITESPACE);
167 if (*arg == '\0') {
168 watch->type = AXA_P_WATCH_ERRORS;
169 return (true);
170 }
171 }
172
173 /* Let the caller handle nonsense watches */
174 emsg->c[0] = '\0';
175 return (false);
176 }
177
178 static bool
get_flag(axa_p_watch_t * watch,u_int bit,char ** strp,const char * flag,size_t flag_len)179 get_flag(axa_p_watch_t *watch, u_int bit,
180 char **strp, const char *flag, size_t flag_len)
181 {
182 char *str;
183
184 str = *strp;
185 if (strncasecmp(str, flag, flag_len) != 0)
186 return (false);
187 str += flag_len;
188 if (*str == ',') {
189 ++str;
190 } else if (*str != ')') {
191 return (false);
192 }
193 watch->flags |= bit;
194 *strp = str;
195 return (true);
196 }
197
198 /*
199 * Parse an RAD watch definition.
200 * An empty emsg->c indicates an unrecognized type of watch.
201 */
202 bool
axa_parse_rad_watch(axa_emsg_t * emsg,axa_p_watch_t * watch,size_t * watch_len,const char * arg)203 axa_parse_rad_watch(axa_emsg_t *emsg,
204 axa_p_watch_t *watch, /* parsed result */
205 size_t *watch_len,
206 const char *arg) /* null terminated */
207 {
208 char *str, *flags;
209
210 str = axa_strdup(arg);
211 flags = strchr(str, '(');
212 if (flags != NULL)
213 *flags++ = '\0';
214
215 if (!axa_parse_watch(emsg, watch, watch_len, str)) {
216 free(str);
217 return (false);
218 }
219
220 switch ((axa_p_watch_type_t)watch->type) {
221 case AXA_P_WATCH_IPV4:
222 case AXA_P_WATCH_IPV6:
223 case AXA_P_WATCH_DNS:
224 break;
225 case AXA_P_WATCH_CH:
226 axa_pemsg(emsg, "channel watches not available");
227 free(str);
228 return (false);
229 case AXA_P_WATCH_ERRORS:
230 axa_pemsg(emsg, "error watches not available");
231 free(str);
232 return (false);
233 default:
234 AXA_FAIL("impossible message type");
235 }
236
237 if (flags != NULL && *flags != '\0') {
238 do {
239 if (get_flag(watch, AXA_P_WATCH_FG_SHARED,
240 &flags, AXA_P_WATCH_STR_SHARED,
241 sizeof(AXA_P_WATCH_STR_SHARED)-1))
242 continue;
243 axa_pemsg(emsg, "unrecognized flag \"(%s\"", flags);
244 free(str);
245 return (false);
246 } while (strcmp(flags, ")") != 0);
247 }
248 free(str);
249 return (true);
250 }
251
252 /* Parse an AXA anomaly detection module definition.
253 * false=problem
254 * emsg->c is a relevant error message except when the watch
255 * makes no sense. In that case, emsg->c[0] == '\0'. */
256 bool
axa_parse_anom(axa_emsg_t * emsg,axa_p_anom_t * anom,size_t * anom_len,const char * arg)257 axa_parse_anom(axa_emsg_t *emsg,
258 axa_p_anom_t *anom, /* parsed result */
259 size_t *anom_len, /* parsed result length */
260 const char *arg) /* null terminated input */
261 {
262 const char *parms;
263 size_t an_len, parms_len;
264
265 memset(anom, 0, sizeof(*anom));
266
267 /* require "name[ parameters]" */
268 if (arg[0] == '\0') {
269 axa_pemsg(emsg, "missing name");
270 return (false);
271 }
272 parms = strpbrk(arg, AXA_WHITESPACE);
273 if (parms == NULL) {
274 an_len = strlen(arg);
275 parms = arg+an_len;
276 } else {
277 an_len = parms - arg;
278 }
279 if (an_len >= sizeof(anom->an)) {
280 axa_pemsg(emsg, "name \"%.*s\" too long",
281 (int)an_len, arg);
282 return (false);
283 }
284 memcpy(&anom->an, arg, an_len);
285
286 parms += strspn(parms, AXA_WHITESPACE);
287 parms_len = strlen(parms)+1;
288 if (parms_len >= sizeof(anom->parms)) {
289 axa_pemsg(emsg, "parameters \"%s\" too long", parms);
290 return (false);
291 }
292 memcpy(&anom->parms, parms, parms_len);
293 *anom_len = sizeof(*anom) - sizeof(anom->parms) + parms_len;
294
295 return (true);
296 }
297
298 const char *
axa_tag_to_str(char * buf,size_t buf_len,axa_tag_t tag)299 axa_tag_to_str(char *buf, size_t buf_len, /* should be AXA_TAG_STRLEN */
300 axa_tag_t tag)
301 {
302 if (tag == AXA_TAG_NONE)
303 strlcpy(buf, "*", buf_len);
304 else
305 snprintf(buf, buf_len, "%d", tag);
306 return (buf);
307 }
308
309 const char *
axa_op_to_str(char * buf,size_t buflen,axa_p_op_t op)310 axa_op_to_str(char *buf, size_t buflen, /* should be AXA_P_OP_STRLEN */
311 axa_p_op_t op)
312 {
313 switch (op) {
314 case AXA_P_OP_HELLO: strlcpy(buf, "HELLO", buflen); break;
315 case AXA_P_OP_NOP: strlcpy(buf, "NOP", buflen); break;
316 case AXA_P_OP_OK: strlcpy(buf, "OK", buflen); break;
317 case AXA_P_OP_ERROR: strlcpy(buf, "ERROR", buflen); break;
318 case AXA_P_OP_WHIT: strlcpy(buf, "WATCH HIT", buflen); break;
319 case AXA_P_OP_AHIT: strlcpy(buf, "ANOMALY HIT", buflen); break;
320 case AXA_P_OP_MISSED: strlcpy(buf, "MISSED", buflen); break;
321 case AXA_P_OP_WLIST: strlcpy(buf, "WATCH LIST", buflen); break;
322 case AXA_P_OP_ALIST: strlcpy(buf, "ANOMALY LIST", buflen); break;
323 case AXA_P_OP_CLIST: strlcpy(buf, "CHANNEL LIST", buflen); break;
324 case AXA_P_OP_MISSED_RAD: strlcpy(buf, "RAD MISSED", buflen); break;
325
326 case AXA_P_OP_USER: strlcpy(buf, "USER", buflen); break;
327 case AXA_P_OP_JOIN: strlcpy(buf, "JOIN", buflen); break;
328 case AXA_P_OP_PAUSE: strlcpy(buf, "PAUSE", buflen); break;
329 case AXA_P_OP_GO: strlcpy(buf, "GO", buflen); break;
330 case AXA_P_OP_WATCH: strlcpy(buf, "WATCH", buflen); break;
331 case AXA_P_OP_WGET: strlcpy(buf, "WATCH GET", buflen); break;
332 case AXA_P_OP_ANOM: strlcpy(buf, "ANOMALY", buflen); break;
333 case AXA_P_OP_AGET: strlcpy(buf, "ANOMALY GET", buflen); break;
334 case AXA_P_OP_STOP: strlcpy(buf, "STOP", buflen); break;
335 case AXA_P_OP_ALL_STOP: strlcpy(buf, "ALL STOP", buflen); break;
336 case AXA_P_OP_CHANNEL: strlcpy(buf, "CHANNEL ON/OFF", buflen); break;
337 case AXA_P_OP_CGET: strlcpy(buf, "CHANNEL GET", buflen); break;
338 case AXA_P_OP_OPT: strlcpy(buf, "OPTION", buflen); break;
339 case AXA_P_OP_ACCT: strlcpy(buf, "ACCOUNTING", buflen); break;
340 case AXA_P_OP_RADU: strlcpy(buf, "RAD UNITS GET", buflen); break;
341 case AXA_P_OP_MGMT_GET: strlcpy(buf, "MGMT GET", buflen); break;
342 case AXA_P_OP_MGMT_GETRSP:strlcpy(buf, "MGMT GET RSP", buflen); break;
343 case _AXA_P_OP_KILL_REQ:strlcpy(buf, "KILL REQ", buflen); break;
344 case _AXA_P_OP_KILL_RSP:strlcpy(buf, "KILL RSP", buflen); break;
345 case _AXA_P_OP_STATS_REQ:strlcpy(buf,"STATS REQ", buflen); break;
346 case _AXA_P_OP_STATS_RSP:strlcpy(buf,"STATS RSP", buflen); break;
347 #pragma clang diagnostic push
348 #pragma clang diagnostic ignored "-Wunreachable-code"
349 default:
350 snprintf(buf, buflen, "unknown op #%d", op);
351 #pragma clang diagnostic pop
352 }
353 return (buf);
354 }
355
356 const char *
axa_opt_to_str(char * buf,size_t buflen,axa_p_opt_type_t opt)357 axa_opt_to_str(char *buf, size_t buflen, axa_p_opt_type_t opt)
358 {
359 switch (opt) {
360 case AXA_P_OPT_TRACE: strlcpy(buf, "TRACE", buflen); break;
361 case AXA_P_OPT_RLIMIT: strlcpy(buf, "RATE LIMIT", buflen); break;
362 case AXA_P_OPT_SAMPLE: strlcpy(buf, "SAMPLE", buflen); break;
363 case AXA_P_OPT_SNDBUF: strlcpy(buf, "SNDBUF", buflen); break;
364 #pragma clang diagnostic push
365 #pragma clang diagnostic ignored "-Wunreachable-code"
366 default:
367 snprintf(buf, buflen, "unknown option type #%d", opt);
368 #pragma clang diagnostic pop
369 }
370 return (buf);
371 }
372
373 const char *
axa_tag_op_to_str(char * buf,size_t buf_len,axa_tag_t tag,axa_p_op_t op)374 axa_tag_op_to_str(char *buf, size_t buf_len,
375 axa_tag_t tag, axa_p_op_t op)
376 {
377 size_t tag_len;
378 char *op_buf;
379
380 axa_tag_to_str(buf, buf_len, tag);
381 tag_len = strlen(buf);
382 if (tag_len+1+1+1 >= buf_len)
383 return (buf);
384 buf_len -= tag_len+2;
385 op_buf = buf + tag_len;
386 *op_buf++ = ' ';
387 axa_op_to_str(op_buf, buf_len - (tag_len+1), op);
388
389 return (buf);
390 }
391
392 char *
axa_watch_ip_to_str(char * buf,size_t buf_len,int af,const void * addr,size_t alen,uint prefix)393 axa_watch_ip_to_str(char *buf, size_t buf_len,
394 int af, const void *addr, size_t alen, uint prefix)
395 {
396 union {
397 struct in_addr ipv4;
398 struct in6_addr ipv6;
399 uint8_t b[0];
400 } abuf;
401 char ip_str[INET6_ADDRSTRLEN];
402 char prefix_str[1+3+1];
403 size_t cplen;
404
405 if (af == AF_INET) {
406 /* Watch IP address lengths are checked in input */
407 if (prefix == 0 || prefix > 32) {
408 snprintf(buf, buf_len,
409 "invalid IPv4 prefix of %d", prefix);
410 return (buf);
411 }
412 if (prefix == 32) {
413 prefix_str[0] = '\0';
414 } else {
415 snprintf(prefix_str, sizeof(prefix_str),
416 "/%d", prefix);
417 }
418 } else {
419 if (prefix == 0 || prefix > 128) {
420 snprintf(buf, buf_len,
421 "invalid IPv6 prefix of %d", prefix);
422 return (buf);
423 }
424 if (prefix == 128) {
425 prefix_str[0] = '\0';
426 } else {
427 snprintf(prefix_str, sizeof(prefix_str), "/%d", prefix);
428 }
429 }
430
431 /* allow truncation to the prefix */
432 memset(&abuf, 0, sizeof(abuf));
433 cplen = alen;
434 if (alen > sizeof(abuf))
435 cplen = sizeof(abuf);
436 memcpy(&abuf, addr, cplen);
437
438 if (NULL == inet_ntop(af, &abuf, ip_str, sizeof(ip_str))) {
439 snprintf(buf, buf_len,
440 "inet_ntop(%c): %s",
441 af == AF_INET ? '4' : '6', strerror(errno));
442 return (buf);
443 }
444 snprintf(buf, buf_len, "IP=%s%s", ip_str, prefix_str);
445 return (buf);
446 }
447
448 char *
axa_watch_to_str(char * buf,size_t buf_len,const axa_p_watch_t * watch,size_t watch_len)449 axa_watch_to_str(char *buf, size_t buf_len,
450 const axa_p_watch_t *watch, size_t watch_len)
451 {
452 char domain[NS_MAXDNAME];
453 const char *star;
454 ssize_t pat_len;
455
456 pat_len = watch_len - (sizeof(*watch) - sizeof(watch->pat));
457 AXA_ASSERT(pat_len >= 0);
458 switch ((axa_p_watch_type_t)watch->type) {
459 case AXA_P_WATCH_IPV4:
460 axa_watch_ip_to_str(buf, buf_len, AF_INET,
461 &watch->pat.addr, pat_len, watch->prefix);
462 break;
463 case AXA_P_WATCH_IPV6:
464 axa_watch_ip_to_str(buf, buf_len, AF_INET6,
465 &watch->pat.addr6, pat_len, watch->prefix);
466 break;
467 case AXA_P_WATCH_DNS:
468 axa_domain_to_str(watch->pat.dns, pat_len,
469 domain, sizeof(domain));
470 if ((watch->flags & AXA_P_WATCH_FG_WILD) == 0) {
471 star = "";
472 } else if (domain[0] == '.') {
473 star = "*";
474 } else {
475 star = "*.";
476 }
477 snprintf(buf, buf_len, "dns=%s%s", star, domain);
478 break;
479 case AXA_P_WATCH_CH:
480 snprintf(buf, buf_len,
481 AXA_OP_CH_PREFIX"="AXA_OP_CH_PREFIX"%d",
482 AXA_P2H_CH(watch->pat.ch));
483 break;
484 case AXA_P_WATCH_ERRORS:
485 snprintf(buf, buf_len, "ERRORS");
486 break;
487 #pragma clang diagnostic push
488 #pragma clang diagnostic ignored "-Wunreachable-code"
489 default:
490 snprintf(buf, buf_len, "unknown watch type %d", watch->type);
491 break;
492 #pragma clang diagnostic pop
493 }
494
495 if ((watch->flags & AXA_P_WATCH_FG_SHARED) != 0)
496 strlcat(buf, "("AXA_P_WATCH_STR_SHARED")", buf_len);
497
498 return (buf);
499 }
500
501 static void
watch_add_str(char ** bufp,size_t * buf_lenp,const char * op_sp,const axa_p_watch_t * watch,size_t watch_len)502 watch_add_str(char **bufp, size_t *buf_lenp,
503 const char *op_sp, const axa_p_watch_t *watch, size_t watch_len)
504 {
505 size_t len;
506
507 axa_buf_print(bufp, buf_lenp, "%s", op_sp);
508 axa_watch_to_str(*bufp, *buf_lenp, watch, watch_len);
509 len = strlen(*bufp);
510 *bufp += len;
511 *buf_lenp -= len;
512 }
513
514 static void
whit_add_str(char ** bufp,size_t * buf_lenp,const char * op_sp,const axa_p_whit_t * whit,size_t whit_len)515 whit_add_str(char **bufp, size_t *buf_lenp,
516 const char *op_sp, const axa_p_whit_t *whit, size_t whit_len)
517 {
518 char ip_str[INET6_ADDRSTRLEN];
519
520 if (whit->hdr.type == AXA_P_WHIT_NMSG) {
521 axa_buf_print(bufp, buf_lenp, "%s"AXA_OP_CH_PREFIX"%d nmsg",
522 op_sp, whit->hdr.ch);
523 return;
524 }
525
526 if (whit->hdr.type != AXA_P_WHIT_IP) {
527 axa_buf_print(bufp, buf_lenp, "%s"AXA_OP_CH_PREFIX"%d ???",
528 op_sp, whit->hdr.ch);
529 return;
530 }
531
532 if (whit_len >= sizeof(struct ip)
533 && (whit->ip.b[0] & 0xf0) == 0x40) {
534 axa_watch_ip_to_str(ip_str, sizeof(ip_str), AF_INET,
535 AXA_OFFSET(whit->ip.b, struct ip, ip_src),
536 4, 32);
537 axa_buf_print(bufp, buf_lenp, "%s"AXA_OP_CH_PREFIX"%d src %s",
538 op_sp, whit->hdr.ch, ip_str);
539
540 } else if (whit_len >= sizeof(struct ip6_hdr)
541 && (whit->ip.b[0] & 0xf0) == 0x60) {
542 axa_watch_ip_to_str(ip_str, sizeof(ip_str), AF_INET6,
543 AXA_OFFSET(whit->ip.b, struct ip6_hdr, ip6_src),
544 16, 128);
545 axa_buf_print(bufp, buf_lenp, "%s"AXA_OP_CH_PREFIX"%d src %s",
546 op_sp, whit->hdr.ch, ip_str);
547
548 } else {
549 axa_buf_print(bufp, buf_lenp, "%s"AXA_OP_CH_PREFIX"%d ???",
550 op_sp, whit->hdr.ch);
551 }
552 }
553
554 static void
rlimit_add_str(char ** bufp,size_t * buf_lenp,axa_cnt_t limit,axa_cnt_t cur,const char * str)555 rlimit_add_str(char **bufp, size_t *buf_lenp,
556 axa_cnt_t limit, axa_cnt_t cur, const char *str)
557 {
558 /* buffers sized largest sane number of packets */
559 char limit_buf[sizeof("9,999,999,999,999,999,999")];
560 char cur_buf[sizeof("; current value=9,999,999,999,999,999,999")];
561 const char *limit_str;
562
563 limit = AXA_P2H64(limit);
564 cur = AXA_P2H64(cur);
565 if (cur == AXA_RLIMIT_NA) {
566 if (limit == AXA_RLIMIT_NA)
567 return;
568 cur_buf[0] = '\0';
569 } else {
570 snprintf(cur_buf, sizeof(cur_buf),
571 "; current value=%"PRIu64, cur);
572 }
573 if (limit == AXA_RLIMIT_NA) {
574 limit_str = "no change";
575 } else if (limit == AXA_RLIMIT_OFF) {
576 limit_str = "unlimited";
577 } else {
578 snprintf(limit_buf, sizeof(limit_buf), "%"PRIu64, limit);
579 limit_str = limit_buf;
580 }
581 axa_buf_print(bufp, buf_lenp, "\n %s per %s%s",
582 limit_str, str, cur_buf);
583 }
584
585 static void
missed_add_str(char ** bufp,size_t * buf_lenp,const char * op_nl,const axa_p_missed_t * missed)586 missed_add_str(char **bufp, size_t *buf_lenp,
587 const char *op_nl, const axa_p_missed_t *missed)
588 {
589 time_t epoch;
590 char time_buf[32];
591
592 epoch = AXA_P2H32(missed->last_report);
593 strftime(time_buf, sizeof(time_buf), "%Y/%m/%d %T",
594 localtime(&epoch));
595
596 axa_buf_print(bufp, buf_lenp,
597 "%s"
598 " missed %"PRIu64" input packets,"
599 " dropped %"PRIu64" for congestion,\n"
600 "\tdropped %"PRIu64" for rate limit,"
601 " filtered %"PRIu64"\n"
602 "\tsince %s",
603 op_nl,
604 AXA_P2H64(missed->missed),
605 AXA_P2H64(missed->dropped),
606 AXA_P2H64(missed->rlimit),
607 AXA_P2H64(missed->filtered),
608 time_buf);
609 }
610
611 static void
missed_rad_add_str(char ** bufp,size_t * buf_lenp,const char * op_nl,const axa_p_missed_rad_t * missed)612 missed_rad_add_str(char **bufp, size_t *buf_lenp,
613 const char *op_nl, const axa_p_missed_rad_t *missed)
614 {
615 time_t epoch;
616 char time_buf[32];
617
618 epoch = AXA_P2H32(missed->last_report);
619 strftime(time_buf, sizeof(time_buf), "%Y/%m/%d %T",
620 localtime(&epoch));
621
622 axa_buf_print(bufp, buf_lenp,
623 "%s"
624 " missed %"PRIu64" input packets at SRA server,"
625 " dropped %"PRIu64" for SRA->RAD congestion,\n"
626 "\tdropped %"PRIu64" for SRA->RAD rate limit,"
627 " filtered %"PRIu64" by SRA\n"
628 "\tdropped %"PRIu64" for RAD->client congestion,"
629 " dropped %"PRIu64" for RAD rate limit,\n"
630 "\tfiltered %"PRIu64" by RAD modules"
631 " since %s",
632 op_nl,
633 AXA_P2H64(missed->sra_missed),
634 AXA_P2H64(missed->sra_dropped),
635 AXA_P2H64(missed->sra_rlimit),
636 AXA_P2H64(missed->sra_filtered),
637 AXA_P2H64(missed->dropped),
638 AXA_P2H64(missed->rlimit),
639 AXA_P2H64(missed->filtered),
640 time_buf);
641 }
642
643 static bool /* false=message added to err_buf */
ck_ipdg(const void * ptr,size_t actual_len,bool is_ip,char ** err_buf,size_t * err_buf_len,const char * proto_nm,size_t min_len,axa_p_ch_t ch)644 ck_ipdg(const void *ptr, size_t actual_len, bool is_ip,
645 char **err_buf, size_t *err_buf_len,
646 const char *proto_nm, size_t min_len, axa_p_ch_t ch)
647 {
648 if (ptr == NULL) {
649 axa_buf_print(err_buf, err_buf_len,
650 "%smissing %s header from "
651 AXA_OP_CH_PREFIX"%d",
652 is_ip ? "" : "\n",
653 proto_nm, ch);
654 return (false);
655 }
656 if (actual_len < min_len) {
657 axa_buf_print(err_buf, err_buf_len,
658 "%struncated %s header of %zd bytes from "
659 AXA_OP_CH_PREFIX"%d",
660 is_ip ? "" : "\n",
661 proto_nm, actual_len, ch);
662 return (false);
663 }
664 return (true);
665 }
666
667 /* Convert a raw IP datagram to a string. */
668 bool /* true=dst and src set */
axa_ipdg_parse(const uint8_t * pkt_data,size_t caplen,axa_p_ch_t ch,axa_socku_t * dst_su,axa_socku_t * src_su,char * cmt,size_t cmt_len)669 axa_ipdg_parse(const uint8_t *pkt_data, size_t caplen, axa_p_ch_t ch,
670 axa_socku_t *dst_su, axa_socku_t *src_su,
671 char *cmt, size_t cmt_len)
672 {
673 struct nmsg_ipdg dg;
674 struct ip ip_hdr;
675 uint ttl;
676 struct ip6_hdr ip6_hdr;
677 struct tcphdr tcp_hdr;
678 struct udphdr udp_hdr;
679 uint uh_ulen;
680 nmsg_res res;
681
682 /* quell static analyzer complaints when dg.proto_network is AF_INET6 */
683 ip_hdr.ip_len = 0;
684
685 memset(dst_su, 0, sizeof(*dst_su));
686 memset(src_su, 0, sizeof(*src_su));
687 if (cmt_len > 0)
688 *cmt = '\0';
689
690 memset(&dg, 0, sizeof(dg));
691 res = nmsg_ipdg_parse_pcap_raw(&dg, DLT_RAW, pkt_data, caplen);
692 if (res != nmsg_res_success || dg.len_network == 0) {
693 axa_buf_print(&cmt, &cmt_len, " unknown packet");
694 return (false);
695 }
696
697 switch (dg.proto_network) {
698 case AF_INET:
699 if (!ck_ipdg(dg.network, dg.len_network, false,
700 &cmt, &cmt_len, "IP", sizeof(ip_hdr), ch))
701 return (false);
702 memcpy(&ip_hdr, dg.network, sizeof(ip_hdr));
703 axa_ip_to_su(dst_su, &ip_hdr.ip_dst, AF_INET);
704 axa_ip_to_su(src_su, &ip_hdr.ip_src, AF_INET);
705 ttl = ip_hdr.ip_ttl;
706 break;
707 case AF_INET6:
708 if (!ck_ipdg(dg.network, dg.len_network, false,
709 &cmt, &cmt_len, "IPv6", sizeof(ip6_hdr), ch))
710 return (false);
711 memcpy(&ip6_hdr, dg.network, sizeof(ip6_hdr));
712 axa_ip_to_su(dst_su, &ip6_hdr.ip6_dst, AF_INET6);
713 axa_ip_to_su(src_su, &ip6_hdr.ip6_src, AF_INET6);
714 ttl = ip6_hdr.ip6_hlim;
715 break;
716 default:
717 axa_buf_print(&cmt, &cmt_len, "unknown AF %d from "
718 AXA_OP_CH_PREFIX"%d",
719 dg.proto_network, AXA_P2H_CH(ch));
720 return (false);
721 }
722
723 switch (dg.proto_transport) {
724 case IPPROTO_ICMP:
725 axa_buf_print(&cmt, &cmt_len, "TTL=%d ICMP", ttl);
726 if (dg.transport == NULL)
727 axa_buf_print(&cmt, &cmt_len, " later fragment");
728 else
729 axa_buf_print(&cmt, &cmt_len,
730 " %d bytes", ntohs(ip_hdr.ip_len));
731 break;
732
733 case IPPROTO_ICMPV6:
734 axa_buf_print(&cmt, &cmt_len, "TTL=%d ICMPv6", ttl);
735 if (dg.transport == NULL)
736 axa_buf_print(&cmt, &cmt_len, " later fragment");
737 break;
738
739 case IPPROTO_TCP:
740 axa_buf_print(&cmt, &cmt_len, "TTL=%d TCP", ttl);
741 if (dg.transport == NULL) {
742 axa_buf_print(&cmt, &cmt_len, " later fragment");
743 } else if (ck_ipdg(dg.transport, dg.len_transport, true,
744 &cmt, &cmt_len, "TCP",
745 sizeof(tcp_hdr), ch )) {
746 memcpy(&tcp_hdr, dg.transport, sizeof(tcp_hdr));
747 AXA_SU_PORT(dst_su) = tcp_hdr.th_dport;
748 AXA_SU_PORT(src_su) = tcp_hdr.th_sport;
749 if ((tcp_hdr.th_flags & TH_FIN) != 0)
750 axa_buf_print(&cmt, &cmt_len, " FIN");
751 if ((tcp_hdr.th_flags & TH_SYN) != 0)
752 axa_buf_print(&cmt, &cmt_len, " SYN");
753 if ((tcp_hdr.th_flags & TH_ACK) != 0)
754 axa_buf_print(&cmt, &cmt_len, " ACK");
755 if ((tcp_hdr.th_flags & TH_RST) != 0)
756 axa_buf_print(&cmt, &cmt_len, " RST");
757 }
758 break;
759
760 case IPPROTO_UDP:
761 axa_buf_print(&cmt, &cmt_len, "TTL=%d UDP", ttl);
762 if (dg.transport == NULL) {
763 axa_buf_print(&cmt, &cmt_len, " later fragment");
764 } else if (ck_ipdg(dg.transport, dg.len_transport, true,
765 &cmt, &cmt_len, "UDP",
766 sizeof(udp_hdr), ch)) {
767 memcpy(&udp_hdr, dg.transport, sizeof(udp_hdr));
768 AXA_SU_PORT(dst_su) = udp_hdr.uh_dport;
769 AXA_SU_PORT(src_su) = udp_hdr.uh_sport;
770 uh_ulen = ntohs(udp_hdr.uh_ulen);
771 axa_buf_print(&cmt, &cmt_len, " %d bytes", uh_ulen);
772 if (uh_ulen != dg.len_payload+sizeof(udp_hdr))
773 axa_buf_print(&cmt, &cmt_len, " fragment");
774 }
775 break;
776
777 default:
778 axa_buf_print(&cmt, &cmt_len, " IP protocol %d",
779 dg.proto_transport);
780 break;
781 }
782
783 return (true);
784 }
785
786 /* Convert some AXA protocol messages to strings. */
787 char * /* input parameter buf0 */
axa_p_to_str(char * buf0,size_t buf_len,bool print_op,const axa_p_hdr_t * hdr,const axa_p_body_t * body)788 axa_p_to_str(char *buf0, size_t buf_len, /* should be AXA_P_STRLEN */
789 bool print_op,
790 const axa_p_hdr_t *hdr, /* protocol byte order */
791 const axa_p_body_t *body)
792 {
793 char tag_op_buf[AXA_TAG_STRLEN+AXA_P_OP_STRLEN];
794 char *buf;
795 char opt_buf[AXA_P_OP_STRLEN];
796 const char *op_sp, *op_nl;
797 uint32_t sample, bufsize;
798
799 buf = buf0;
800 buf[0] = '\0';
801 if (print_op) {
802 axa_buf_print(&buf, &buf_len, "%s",
803 axa_tag_op_to_str(tag_op_buf, sizeof(tag_op_buf),
804 AXA_P2H_TAG(hdr->tag),
805 hdr->op));
806 op_sp = " ";
807 op_nl = "\n";
808 } else {
809 op_sp = "";
810 op_nl = "";
811 }
812
813 switch ((axa_p_op_t)hdr->op) {
814 case AXA_P_OP_NOP:
815 break;
816
817 case AXA_P_OP_HELLO:
818 axa_buf_print(&buf, &buf_len, "%s%s", op_sp, body->hello.str);
819 break;
820
821 case AXA_P_OP_OK:
822 case AXA_P_OP_ERROR:
823 if (body->result.orig_op == AXA_P_OP_OK
824 || body->result.orig_op == AXA_P_OP_NOP
825 || body->result.orig_op == AXA_P_OP_ERROR) {
826 axa_buf_print(&buf, &buf_len, "%s%s",
827 op_sp, body->result.str);
828 } else {
829 axa_buf_print(&buf, &buf_len, "%s%s %s",
830 op_sp,
831 axa_op_to_str(tag_op_buf,
832 sizeof(tag_op_buf),
833 body->result.orig_op),
834 body->result.str);
835 }
836 break;
837
838 case AXA_P_OP_MISSED:
839 missed_add_str(&buf, &buf_len, op_nl, &body->missed);
840 break;
841
842 case AXA_P_OP_MISSED_RAD:
843 missed_rad_add_str(&buf, &buf_len, op_nl, &body->missed_rad);
844 break;
845
846 case AXA_P_OP_WHIT:
847 whit_add_str(&buf, &buf_len, op_sp, &body->whit,
848 (AXA_P2H32(hdr->len) - sizeof(*hdr)));
849 break;
850
851 case AXA_P_OP_WATCH:
852 watch_add_str(&buf, &buf_len, op_sp, &body->watch,
853 (AXA_P2H32(hdr->len) - sizeof(*hdr)));
854 break;
855
856 case AXA_P_OP_ANOM:
857 axa_buf_print(&buf, &buf_len, "%s%s", op_sp, body->anom.an.c);
858 if (AXA_P2H32(hdr->len)-sizeof(*hdr) > sizeof(body->anom.an.c)
859 && body->anom.parms[0] != '\0')
860 axa_buf_print(&buf, &buf_len, " %s", body->anom.parms);
861 break;
862
863 case AXA_P_OP_CHANNEL:
864 if (body->channel.ch == AXA_P2H_CH(AXA_OP_CH_ALL)) {
865 snprintf(buf, buf_len, "%s"AXA_OP_CH_ALLSTR" %s",
866 op_sp,
867 (body->channel.on != 0) ? "on" : "off");
868 } else {
869 snprintf(buf, buf_len, "%s"AXA_OP_CH_PREFIX"%d %s",
870 op_sp,
871 AXA_P2H_CH(body->channel.ch),
872 (body->channel.on != 0) ? "on" : "off");
873 }
874 break;
875
876 case AXA_P_OP_WLIST:
877 if (print_op)
878 axa_buf_print(&buf, &buf_len, " %5s",
879 axa_tag_to_str(tag_op_buf,
880 sizeof(tag_op_buf),
881 AXA_P2H_TAG(body
882 ->wlist.cur_tag)));
883 watch_add_str(&buf, &buf_len, op_sp, &body->wlist.w,
884 (AXA_P2H32(hdr->len) - sizeof(*hdr)
885 - (sizeof(body->wlist)
886 - sizeof(body->wlist.w))));
887 break;
888
889 case AXA_P_OP_AHIT:
890 axa_buf_print(&buf, &buf_len, "%s%s ", op_sp, body->ahit.an.c);
891 whit_add_str(&buf, &buf_len, op_sp, &body->ahit.whit,
892 (AXA_P2H32(hdr->len) - sizeof(*hdr)));
893 break;
894
895 case AXA_P_OP_ALIST:
896 if (print_op)
897 axa_buf_print(&buf, &buf_len, " %5s ",
898 axa_tag_to_str(tag_op_buf,
899 sizeof(tag_op_buf),
900 AXA_P2H_TAG(body
901 ->alist.cur_tag)));
902 axa_buf_print(&buf, &buf_len, "%5s %s",
903 body->alist.anom.an.c,
904 body->alist.anom.parms);
905 break;
906
907 case AXA_P_OP_CLIST:
908 break;
909
910 case AXA_P_OP_USER:
911 axa_buf_print(&buf, &buf_len, "%s'%s'",
912 op_sp, body->user.name);
913 break;
914
915 case AXA_P_OP_OPT:
916 switch ((axa_p_opt_type_t)body->opt.type) {
917 case AXA_P_OPT_TRACE:
918 axa_buf_print(&buf, &buf_len, "%strace=%d", op_sp,
919 AXA_P2H32(body->opt.u.trace));
920 break;
921 case AXA_P_OPT_RLIMIT:
922 axa_buf_print(&buf, &buf_len, "%s%s", op_sp,
923 axa_opt_to_str(opt_buf, sizeof(opt_buf),
924 body->opt.type));
925 rlimit_add_str(&buf, &buf_len,
926 body->opt.u.rlimit.max_pkts_per_sec,
927 body->opt.u.rlimit.cur_pkts_per_sec,
928 "second");
929 if (AXA_P2H64(body->opt.u.rlimit.report_secs)
930 == AXA_RLIMIT_OFF)
931 axa_buf_print(&buf, &buf_len,
932 " no regular reports");
933 else if (AXA_P2H64(body->opt.u.rlimit.report_secs)
934 != AXA_RLIMIT_NA)
935 axa_buf_print(&buf, &buf_len,
936 "\n %"PRIu64
937 " seconds between reports",
938 AXA_P2H64(body->opt.u.
939 rlimit.report_secs));
940 break;
941 case AXA_P_OPT_SAMPLE:
942 sample = AXA_P2H32(body->opt.u.sample);
943 if (sample == AXA_P_OPT_SAMPLE_REQ)
944 axa_buf_print(&buf, &buf_len,
945 "%srequest sample rate",
946 op_sp);
947 else
948 axa_buf_print(&buf, &buf_len,
949 "%ssample %.2f%%",
950 op_sp,
951 sample
952 / (AXA_P_OPT_SAMPLE_SCALE*1.0));
953 break;
954 case AXA_P_OPT_SNDBUF:
955 bufsize = AXA_P2H32(body->opt.u.bufsize);
956 if (bufsize == AXA_P_OPT_SNDBUF_REQ)
957 axa_buf_print(&buf, &buf_len,
958 "%srequest bufsize",
959 op_sp);
960 else
961 axa_buf_print(&buf, &buf_len, "%sbufsize=%d",
962 op_sp, bufsize);
963 break;
964 #pragma clang diagnostic push
965 #pragma clang diagnostic ignored "-Wunreachable-code"
966 default:
967 if (print_op)
968 axa_buf_print(&buf, &buf_len, " ");
969 axa_buf_print(&buf, &buf_len,
970 "unrecognized type %d", body->opt.type);
971 break;
972 #pragma clang diagnostic pop
973 }
974 break;
975
976 case AXA_P_OP_JOIN:
977 case AXA_P_OP_PAUSE:
978 case AXA_P_OP_GO:
979 case AXA_P_OP_WGET:
980 case AXA_P_OP_AGET:
981 case AXA_P_OP_STOP:
982 case AXA_P_OP_ALL_STOP:
983 case AXA_P_OP_CGET:
984 case AXA_P_OP_ACCT:
985 case AXA_P_OP_RADU:
986 case AXA_P_OP_MGMT_GET:
987 case AXA_P_OP_MGMT_GETRSP:
988 case _AXA_P_OP_KILL_REQ:
989 case _AXA_P_OP_KILL_RSP:
990 case _AXA_P_OP_STATS_REQ:
991 case _AXA_P_OP_STATS_RSP:
992 default:
993 break;
994 }
995
996 return (buf0);
997 }
998
999 /* Check the header of an AXA message. */
1000 bool /* false=bad */
axa_ck_hdr(axa_emsg_t * emsg,const axa_p_hdr_t * hdr,const char * label,axa_p_direction_t dir)1001 axa_ck_hdr(axa_emsg_t *emsg, const axa_p_hdr_t *hdr,
1002 const char *label, axa_p_direction_t dir)
1003 {
1004 size_t max_len, min_len;
1005 bool dir_ok;
1006 const char *dir1_str, *dir2_str;
1007 int tagged; /* -1=never 0=sometimes 1=always */
1008 char op_buf[AXA_P_OP_STRLEN];
1009 axa_p_body_t *body;
1010 axa_tag_t tag;
1011 uint32_t len;
1012
1013 body = NULL;
1014 len = AXA_P2H32(hdr->len);
1015 if (len < sizeof(*hdr)) {
1016 axa_pemsg(emsg, "AXA header length of %d is too small"
1017 " from %s", len, label);
1018 return (false);
1019 }
1020 if (hdr->pvers < AXA_P_PVERS_MIN || hdr->pvers > AXA_P_PVERS_MAX) {
1021 axa_pemsg(emsg, "unknown protocol version #%d for %s from %s",
1022 hdr->pvers,
1023 axa_op_to_str(op_buf, sizeof(op_buf), hdr->op),
1024 label);
1025 return (false);
1026 }
1027 len -= sizeof(*hdr);
1028 if (len > AXA_P_MAX_BODY_LEN) {
1029 axa_pemsg(emsg, "impossible body length %d from %s",
1030 len, label);
1031 return (false);
1032 }
1033
1034 switch ((axa_p_op_t)hdr->op) {
1035 case AXA_P_OP_NOP:
1036 max_len = min_len = 0;
1037 tagged = 0;
1038 dir_ok = true;
1039 break;
1040 case AXA_P_OP_HELLO:
1041 max_len = sizeof(body->hello);
1042 min_len = max_len - sizeof(body->hello.str);
1043 tagged = -1;
1044 dir_ok = true;
1045 break;
1046 case AXA_P_OP_OK:
1047 case AXA_P_OP_ERROR:
1048 max_len = sizeof(body->result);
1049 min_len = max_len - sizeof(body->result.str);
1050 tagged = 0;
1051 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1052 break;
1053 case AXA_P_OP_MISSED:
1054 max_len = min_len = sizeof(body->missed);
1055 tagged = -1;
1056 dir_ok = (dir == AXA_P_FROM_SRA);
1057 break;
1058 case AXA_P_OP_MISSED_RAD:
1059 max_len = min_len = sizeof(body->missed_rad);
1060 tagged = -1;
1061 dir_ok = (dir == AXA_P_FROM_RAD);
1062 break;
1063 case AXA_P_OP_WHIT:
1064 min_len = AXA_WHIT_MIN_LEN;
1065 max_len = AXA_WHIT_MAX_LEN;
1066 tagged = 1;
1067 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1068 break;
1069 case AXA_P_OP_WLIST:
1070 max_len = sizeof(body->wlist);
1071 min_len = max_len - sizeof(body->wlist.w.pat);
1072 tagged = 0;
1073 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1074 break;
1075 case AXA_P_OP_AHIT:
1076 min_len = (sizeof(body->ahit) - sizeof(body->ahit.whit)
1077 + AXA_WHIT_MIN_LEN);
1078 max_len = (sizeof(body->ahit) - sizeof(body->ahit.whit)
1079 + AXA_WHIT_MAX_LEN);
1080 tagged = 1;
1081 dir_ok = (dir == AXA_P_FROM_RAD);
1082 break;
1083 case AXA_P_OP_ALIST:
1084 max_len = sizeof(body->alist);
1085 min_len = max_len - sizeof(body->alist.anom.parms);
1086 tagged = 0;
1087 dir_ok = (dir == AXA_P_FROM_RAD);
1088 break;
1089 case AXA_P_OP_CLIST:
1090 max_len = sizeof(body->clist);
1091 min_len = max_len;
1092 tagged = 0;
1093 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1094 break;
1095
1096 case AXA_P_OP_USER:
1097 max_len = min_len = sizeof(body->user);
1098 tagged = 0;
1099 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1100 break;
1101 case AXA_P_OP_JOIN:
1102 max_len = min_len = sizeof(body->join);
1103 tagged = 0;
1104 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1105 break;
1106 case AXA_P_OP_PAUSE:
1107 case AXA_P_OP_GO:
1108 max_len = min_len = 0;
1109 tagged = 0;
1110 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1111 break;
1112 case AXA_P_OP_WATCH:
1113 max_len = sizeof(body->watch);
1114 min_len = max_len - sizeof(body->watch.pat);
1115 tagged = 1;
1116 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1117 break;
1118 case AXA_P_OP_WGET:
1119 max_len = min_len = 0;
1120 tagged = 0;
1121 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1122 break;
1123 case AXA_P_OP_ANOM:
1124 max_len = sizeof(body->anom);
1125 min_len = max_len - sizeof(body->anom.parms);
1126 tagged = 1;
1127 dir_ok = (dir == AXA_P_TO_RAD);
1128 break;
1129 case AXA_P_OP_AGET:
1130 max_len = min_len = 0;
1131 tagged = 0;
1132 dir_ok = (dir == AXA_P_TO_RAD);
1133 break;
1134 case AXA_P_OP_STOP:
1135 max_len = min_len = 0;
1136 tagged = 1;
1137 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1138 break;
1139 case AXA_P_OP_ALL_STOP:
1140 max_len = min_len = 0;
1141 tagged = 0;
1142 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1143 break;
1144 case AXA_P_OP_CHANNEL:
1145 max_len = sizeof(axa_p_channel_t);
1146 min_len = max_len;
1147 tagged = 0;
1148 dir_ok = (dir == AXA_P_TO_SRA);
1149 break;
1150 case AXA_P_OP_CGET:
1151 max_len = min_len = 0;
1152 tagged = 0;
1153 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1154 break;
1155 case AXA_P_OP_OPT:
1156 min_len = sizeof(body->opt) - sizeof(body->opt.u);
1157 max_len = min_len + 1024;
1158 tagged = 0;
1159 dir_ok = true;
1160 break;
1161 case AXA_P_OP_ACCT:
1162 max_len = min_len = 0;
1163 tagged = 0;
1164 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1165 break;
1166 case AXA_P_OP_RADU:
1167 max_len = min_len = 0;
1168 tagged = 0;
1169 dir_ok = (dir == AXA_P_TO_RAD);
1170 break;
1171 case AXA_P_OP_MGMT_GET:
1172 max_len = min_len = 0;
1173 tagged = 0;
1174 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1175 break;
1176 case AXA_P_OP_MGMT_GETRSP:
1177 min_len = max_len =
1178 strlen("mgmt is deprecated, please upgrade and use \"stats\"");
1179 tagged = 0;
1180 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1181 break;
1182 case _AXA_P_OP_KILL_REQ:
1183 max_len = min_len = sizeof(_axa_p_kill_t);
1184 tagged = 0;
1185 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1186 break;
1187 case _AXA_P_OP_KILL_RSP:
1188 min_len = max_len = sizeof(_axa_p_kill_t);
1189 tagged = 0;
1190 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1191 break;
1192 case _AXA_P_OP_STATS_REQ:
1193 max_len = min_len = sizeof(_axa_p_stats_req_t);
1194 tagged = 0;
1195 dir_ok = (dir == AXA_P_TO_SRA || dir == AXA_P_TO_RAD);
1196 break;
1197 case _AXA_P_OP_STATS_RSP:
1198 /* stats response header */
1199 min_len = sizeof(_axa_p_stats_rsp_t);
1200 /* stats response header + sys object + max user objs + max
1201 * rad an objs */
1202 max_len = sizeof(_axa_p_stats_rsp_t) +
1203 sizeof(_axa_p_stats_sys_t) +
1204 (_AXA_STATS_MAX_USER_OBJS *
1205 sizeof(_axa_p_stats_user_t)) +
1206 (_AXA_STATS_MAX_USER_OBJS *
1207 ((_AXA_STATS_MAX_USER_RAD_AN_OBJS *
1208 sizeof(_axa_p_stats_user_rad_an_t))));
1209 tagged = 0;
1210 dir_ok = (dir == AXA_P_FROM_SRA || dir == AXA_P_FROM_RAD);
1211 break;
1212
1213 #pragma clang diagnostic push
1214 #pragma clang diagnostic ignored "-Wunreachable-code"
1215 default:
1216 max_len = 0;
1217 min_len = INT_MAX;
1218 tagged = 1;
1219 dir_ok = false;
1220 break;
1221 #pragma clang diagnostic pop
1222 }
1223
1224 tag = AXA_P2H_TAG(hdr->tag);
1225 if (tagged == 1) {
1226 if (tag == AXA_TAG_NONE) {
1227 axa_pemsg(emsg, "missing tag for %s from %s",
1228 axa_op_to_str(op_buf, sizeof(op_buf),
1229 hdr->op),
1230 label);
1231 return (false);
1232 }
1233 } else if (tagged == -1) {
1234 if (tag != AXA_TAG_NONE) {
1235 axa_pemsg(emsg, "unexpected tag %d for %s from %s",
1236 tag,
1237 axa_op_to_str(op_buf, sizeof(op_buf),
1238 hdr->op),
1239 label);
1240 return (false);
1241 }
1242 }
1243
1244 if (!dir_ok) {
1245 switch (dir) {
1246 case AXA_P_TO_SRA:
1247 dir1_str = label;
1248 dir2_str = "SRA client";
1249 break;
1250 case AXA_P_FROM_SRA:
1251 dir1_str = "SRA";
1252 dir2_str = label;
1253 break;
1254 case AXA_P_TO_RAD:
1255 dir1_str = label;
1256 dir2_str = "RAD client";
1257 break;
1258 case AXA_P_FROM_RAD:
1259 dir1_str = "RAD";
1260 dir2_str = label;
1261 break;
1262 #pragma clang diagnostic push
1263 #pragma clang diagnostic ignored "-Wunreachable-code"
1264 default:
1265 dir1_str = "?";
1266 dir2_str = label;
1267 break;
1268 #pragma clang diagnostic pop
1269 }
1270 axa_pemsg(emsg, "%s illegal from %s to %s",
1271 axa_op_to_str(op_buf, sizeof(op_buf), hdr->op),
1272 dir1_str, dir2_str);
1273 return (false);
1274 }
1275
1276 if (len > max_len) {
1277 axa_pemsg(emsg, "length %d for %s from %s should be at most %zu",
1278 len, axa_op_to_str(op_buf, sizeof(op_buf), hdr->op),
1279 label, max_len);
1280 return (false);
1281 }
1282 if (len < min_len) {
1283 axa_pemsg(emsg, "length %d for %s from %s must be at least %zu",
1284 len, axa_op_to_str(op_buf, sizeof(op_buf), hdr->op),
1285 label, min_len);
1286 return (false);
1287 }
1288
1289 return (true);
1290 }
1291
1292 /* Check that an AXA message is null terminated. */
1293 static bool
ck_field_null(axa_emsg_t * emsg,axa_p_op_t op,const void * field,size_t field_len,const char * field_name)1294 ck_field_null(axa_emsg_t *emsg, axa_p_op_t op, const void *field,
1295 size_t field_len, const char *field_name)
1296 {
1297 char op_buf[AXA_P_OP_STRLEN];
1298
1299 if (field_len == 0) {
1300 axa_pemsg(emsg, "%s %s truncated",
1301 axa_op_to_str(op_buf, sizeof(op_buf), op),
1302 field_name);
1303 return (false);
1304 }
1305 if (((uint8_t *)field)[field_len-1] != '\0') {
1306 axa_pemsg(emsg, "%s %s not null terminated",
1307 axa_op_to_str(op_buf, sizeof(op_buf), op),
1308 field_name);
1309 return (false);
1310 }
1311 return (true);
1312 }
1313
1314 /* Check a binary channel number. */
1315 static bool
ck_ch(axa_emsg_t * emsg,axa_p_op_t op,axa_p_ch_t ch,bool all_ok)1316 ck_ch(axa_emsg_t *emsg, axa_p_op_t op,
1317 axa_p_ch_t ch, /* protocol byte order */
1318 bool all_ok)
1319 {
1320 char op_buf[AXA_P_OP_STRLEN];
1321
1322 ch = AXA_P2H_CH(ch);
1323 if (ch == AXA_OP_CH_ALL && all_ok)
1324 return (true);
1325 if (ch > AXA_OP_CH_MAX) {
1326 axa_pemsg(emsg, "%s "AXA_OP_CH_PREFIX"%d is an invalid channel",
1327 axa_op_to_str(op_buf, sizeof(op_buf), op), ch);
1328 return (false);
1329 }
1330 return (true);
1331 }
1332
1333 /* Check anomaly name */
1334 static bool
ck_an(axa_emsg_t * emsg,axa_p_op_t op,const axa_p_an_t * an)1335 ck_an(axa_emsg_t *emsg, axa_p_op_t op, const axa_p_an_t *an)
1336 {
1337 char op_buf[AXA_P_OP_STRLEN];
1338
1339 if (an->c[sizeof(an->c)-1] != '\0') {
1340 axa_pemsg(emsg, "%s \"%.*s\" name not null terminated",
1341 axa_op_to_str(op_buf, sizeof(op_buf), op),
1342 (int)sizeof(*an), an->c);
1343 return (false);
1344 }
1345 return (true);
1346 }
1347
1348 /* Check anomaly specification. */
1349 static bool
ck_anom(axa_emsg_t * emsg,axa_p_op_t op,const axa_p_anom_t * anom,size_t anom_len)1350 ck_anom(axa_emsg_t *emsg, axa_p_op_t op,
1351 const axa_p_anom_t *anom, size_t anom_len)
1352 {
1353 size_t parms_len;
1354
1355 parms_len = anom_len - sizeof(anom->an);
1356 return (ck_field_null(emsg, op, anom->an.c, sizeof(anom->an), "name")
1357 && (parms_len == 0
1358 || ck_field_null(emsg, op, anom->parms, parms_len,
1359 "parameters")));
1360 }
1361
1362 /* Check a watch in AXA_P_OP_WATCH or AXA_P_OP_WLIST. */
1363 static bool
ck_watch(axa_emsg_t * emsg,axa_p_op_t op,const axa_p_watch_t * w,size_t watch_len)1364 ck_watch(axa_emsg_t *emsg, axa_p_op_t op,
1365 const axa_p_watch_t *w, size_t watch_len)
1366 {
1367 char op_buf[AXA_P_OP_STRLEN];
1368 ssize_t pat_len;
1369 int name_len;
1370
1371 if (w->pad != 0) {
1372 axa_pemsg(emsg, "%s bad watch byte %#x",
1373 axa_op_to_str(op_buf, sizeof(op_buf), op),
1374 w->pad);
1375 return (false);
1376 }
1377 if (0 != (w->flags & ~(AXA_P_WATCH_FG_WILD
1378 | AXA_P_WATCH_FG_SHARED))) {
1379 axa_pemsg(emsg, "%s bad watch flags %#x",
1380 axa_op_to_str(op_buf, sizeof(op_buf), op),
1381 w->flags);
1382 return (false);
1383 }
1384
1385 pat_len = watch_len - (sizeof(*w) - sizeof(w->pat));
1386 switch ((axa_p_watch_type_t)w->type) {
1387 case AXA_P_WATCH_IPV4:
1388 if (pat_len <= 0 || pat_len > (ssize_t)sizeof(w->pat.addr)) {
1389 axa_pemsg(emsg, "%s bad IPv4 length %zd",
1390 axa_op_to_str(op_buf, sizeof(op_buf), op),
1391 watch_len);
1392 return (false);
1393 }
1394 if (w->prefix == 0 || (w->prefix+7)/8 > pat_len) {
1395 axa_pemsg(emsg, "%s bad prefix length"
1396 " %d for address length %zd",
1397 axa_op_to_str(op_buf, sizeof(op_buf), op),
1398 w->prefix, pat_len);
1399 return (false);
1400 }
1401 break;
1402 case AXA_P_WATCH_IPV6:
1403 if (pat_len <= 0 || pat_len > (ssize_t)sizeof(w->pat.addr6)) {
1404 axa_pemsg(emsg, "%s bad IPv6 length %zd",
1405 axa_op_to_str(op_buf, sizeof(op_buf), op),
1406 watch_len);
1407 return (false);
1408 }
1409 if (w->prefix == 0 || (w->prefix+7)/8 > pat_len) {
1410 axa_pemsg(emsg, "%s bad prefix length"
1411 " %d for address length %zd",
1412 axa_op_to_str(op_buf, sizeof(op_buf), op),
1413 w->prefix, pat_len);
1414 return (false);
1415 }
1416 break;
1417 case AXA_P_WATCH_DNS:
1418 if (pat_len <= 0 || pat_len > (int)sizeof(w->pat.dns)) {
1419 axa_pemsg(emsg, "%s bad dns length %zd",
1420 axa_op_to_str(op_buf, sizeof(op_buf), op),
1421 watch_len);
1422 return (false);
1423 }
1424 name_len = 0;
1425 while (w->pat.dns[name_len] != 0) {
1426 name_len += 1+w->pat.dns[name_len];
1427 if (name_len > pat_len)
1428 break;
1429 }
1430 if (name_len+1 != pat_len) {
1431 axa_pemsg(emsg, "%s bad dns label lengths",
1432 axa_op_to_str(op_buf, sizeof(op_buf), op));
1433 return (false);
1434 }
1435 break;
1436 case AXA_P_WATCH_CH:
1437 if (pat_len != sizeof(w->pat.ch)) {
1438 axa_pemsg(emsg, "%s bad channel watch length %zd",
1439 axa_op_to_str(op_buf, sizeof(op_buf), op),
1440 watch_len);
1441 return (false);
1442 }
1443 return (ck_ch(emsg, op, w->pat.ch, false));
1444 case AXA_P_WATCH_ERRORS:
1445 if (pat_len != 0) {
1446 axa_pemsg(emsg, "%s bad error watch length %zd",
1447 axa_op_to_str(op_buf, sizeof(op_buf), op),
1448 watch_len);
1449 return (false);
1450 }
1451 break;
1452 #pragma clang diagnostic push
1453 #pragma clang diagnostic ignored "-Wunreachable-code"
1454 default:
1455 axa_pemsg(emsg, "%s unknown watch type %d",
1456 axa_op_to_str(op_buf, sizeof(op_buf), op),
1457 w->type);
1458 return (false);
1459 #pragma clang diagnostic pop
1460 }
1461
1462 return (true);
1463 }
1464
1465 static bool
ck_whit(axa_emsg_t * emsg,axa_p_op_t op,const axa_p_whit_t * whit,size_t whit_len)1466 ck_whit(axa_emsg_t *emsg, axa_p_op_t op,
1467 const axa_p_whit_t *whit, size_t whit_len)
1468 {
1469 char op_buf[AXA_P_OP_STRLEN];
1470
1471 if (!ck_ch(emsg, op, whit->hdr.ch, false))
1472 return (false);
1473
1474 if (whit->hdr.type == AXA_P_WHIT_NMSG) {
1475 if (whit_len < sizeof(axa_p_whit_nmsg_t)) {
1476 axa_pemsg(emsg, "%s bad nmsg watch hit length %zd",
1477 axa_op_to_str(op_buf, sizeof(op_buf), op),
1478 whit_len);
1479 return (false);
1480 }
1481
1482 } else if (whit->hdr.type == AXA_P_WHIT_IP) {
1483 if (whit_len < sizeof(axa_p_whit_ip_t)) {
1484 axa_pemsg(emsg, "%s bad IP watch hit length %zd",
1485 axa_op_to_str(op_buf, sizeof(op_buf), op),
1486 whit_len);
1487 return (false);
1488 }
1489
1490 } else {
1491 axa_pemsg(emsg, "%s bad watch hit type %d",
1492 axa_op_to_str(op_buf, sizeof(op_buf), op),
1493 whit->hdr.type);
1494 return (false);
1495 }
1496
1497 return (true);
1498 }
1499
1500 static bool
ck_opt(axa_emsg_t * emsg,axa_p_op_t op,const axa_p_opt_t * opt,size_t opt_len)1501 ck_opt(axa_emsg_t *emsg, axa_p_op_t op, const axa_p_opt_t *opt, size_t opt_len)
1502 {
1503 size_t val_len;
1504 char op_buf[AXA_P_OP_STRLEN];
1505 char opt_buf[AXA_P_OP_STRLEN];
1506
1507 AXA_ASSERT(opt_len >= sizeof(axa_p_opt_t) - sizeof(opt->u));
1508
1509 switch ((axa_p_opt_type_t)opt->type) {
1510 case AXA_P_OPT_TRACE:
1511 val_len = sizeof(opt->u.trace);
1512 break;
1513 case AXA_P_OPT_RLIMIT:
1514 val_len = sizeof(opt->u.rlimit);
1515 break;
1516 case AXA_P_OPT_SAMPLE:
1517 val_len = sizeof(opt->u.sample);
1518 break;
1519 case AXA_P_OPT_SNDBUF:
1520 val_len = sizeof(opt->u.bufsize);
1521 break;
1522 #pragma clang diagnostic push
1523 #pragma clang diagnostic ignored "-Wunreachable-code"
1524 default:
1525 axa_pemsg(emsg, "%s %s",
1526 axa_op_to_str(op_buf, sizeof(op_buf), op),
1527 axa_opt_to_str(opt_buf, sizeof(opt_buf), opt->type));
1528 return (false);
1529 #pragma clang diagnostic pop
1530 }
1531
1532 if (val_len != opt_len - (sizeof(axa_p_opt_t) - sizeof(opt->u))) {
1533 axa_pemsg(emsg, "%s %s bad rate limit option length %zd",
1534 axa_op_to_str(op_buf, sizeof(op_buf), op),
1535 axa_opt_to_str(opt_buf, sizeof(opt_buf), opt->type),
1536 opt_len);
1537 return (false);
1538 }
1539
1540 return (true);
1541 }
1542
1543 /*
1544 * Sanity check an AXA protocol body after the header has been checked.
1545 * The header check has validated the body length.
1546 */
1547 bool /* false=bad */
axa_ck_body(axa_emsg_t * emsg,axa_p_op_t op,const axa_p_body_t * body,size_t body_len)1548 axa_ck_body(axa_emsg_t *emsg, axa_p_op_t op, const axa_p_body_t *body,
1549 size_t body_len)
1550 {
1551 switch (op) {
1552 case AXA_P_OP_HELLO:
1553 return (ck_field_null(emsg, op, body->b, body_len, "version"));
1554 case AXA_P_OP_NOP:
1555 break;
1556 case AXA_P_OP_OK:
1557 case AXA_P_OP_ERROR:
1558 return (ck_field_null(emsg, op, body, body_len, "message"));
1559 case AXA_P_OP_MISSED:
1560 case AXA_P_OP_MISSED_RAD:
1561 break;
1562 case AXA_P_OP_WHIT:
1563 return (ck_whit(emsg, op, &body->whit, body_len));
1564 case AXA_P_OP_WLIST:
1565 return (ck_watch(emsg, op, &body->wlist.w,
1566 body_len - (sizeof(body->wlist)
1567 - sizeof(body->wlist.w))));
1568 case AXA_P_OP_AHIT:
1569 return (ck_an(emsg, op, &body->ahit.an)
1570 && ck_ch(emsg, op, body->ahit.whit.hdr.ch, false));
1571 case AXA_P_OP_ALIST:
1572 return (ck_anom(emsg, op, &body->alist.anom,
1573 body_len - (sizeof(body->alist)
1574 - sizeof(body->alist.anom))));
1575 case AXA_P_OP_CLIST:
1576 if (!ck_ch(emsg, op, body->clist.ch, false))
1577 return (false);
1578 return (ck_field_null(emsg, op, body, body_len, "channel"));
1579
1580
1581 case AXA_P_OP_USER:
1582 return (ck_field_null(emsg, op, body, body_len, "user name"));
1583 case AXA_P_OP_JOIN:
1584 case AXA_P_OP_PAUSE:
1585 case AXA_P_OP_GO:
1586 break;
1587 case AXA_P_OP_WATCH:
1588 return (ck_watch(emsg, op, &body->watch, body_len));
1589 case AXA_P_OP_WGET:
1590 break;
1591 case AXA_P_OP_ANOM:
1592 return (ck_anom(emsg, op, &body->anom, body_len));
1593 case AXA_P_OP_AGET:
1594 case AXA_P_OP_STOP:
1595 case AXA_P_OP_ALL_STOP:
1596 break;
1597 case AXA_P_OP_CHANNEL:
1598 return (ck_ch(emsg, op, body->channel.ch, true));
1599 case AXA_P_OP_CGET:
1600 break;
1601 case AXA_P_OP_OPT:
1602 return (ck_opt(emsg, op, &body->opt, body_len));
1603 case AXA_P_OP_ACCT:
1604 break;
1605 case AXA_P_OP_RADU:
1606 break;
1607 case AXA_P_OP_MGMT_GET:
1608 break;
1609 case AXA_P_OP_MGMT_GETRSP:
1610 break;
1611 case _AXA_P_OP_KILL_REQ:
1612 /* TODO */
1613 break;
1614 case _AXA_P_OP_KILL_RSP:
1615 /* TODO */
1616 break;
1617 case _AXA_P_OP_STATS_REQ:
1618 /* TODO */
1619 break;
1620 case _AXA_P_OP_STATS_RSP:
1621 /* TODO */
1622 break;
1623 }
1624
1625 return (true);
1626 }
1627
1628 axa_io_type_t
axa_io_type_parse(const char ** addrp)1629 axa_io_type_parse(const char **addrp)
1630 {
1631 axa_io_type_t result;
1632 const char *addr;
1633 int i;
1634
1635 addr = *addrp;
1636 addr += strspn(addr, AXA_WHITESPACE);
1637
1638 if (AXA_CLITCMP(addr, AXA_IO_TYPE_UNIX_STR":")) {
1639 addr += sizeof(AXA_IO_TYPE_UNIX_STR":")-1;
1640 result = AXA_IO_TYPE_UNIX;
1641
1642 } else if (AXA_CLITCMP(addr, AXA_IO_TYPE_TCP_STR":")) {
1643 addr += sizeof(AXA_IO_TYPE_TCP_STR":")-1;
1644 result = AXA_IO_TYPE_TCP;
1645
1646 } else if (AXA_CLITCMP(addr, AXA_IO_TYPE_TLS_STR":")) {
1647 addr += sizeof(AXA_IO_TYPE_TLS_STR":")-1;
1648 result = AXA_IO_TYPE_TLS;
1649
1650 } else if (AXA_CLITCMP(addr, AXA_IO_TYPE_SSH_STR":")) {
1651 addr += sizeof(AXA_IO_TYPE_SSH_STR":")-1;
1652 result = AXA_IO_TYPE_SSH;
1653
1654 } else if (AXA_CLITCMP(addr, AXA_IO_TYPE_SSH_STR)
1655 && 0 != (i = strspn(addr+sizeof(AXA_IO_TYPE_SSH_STR)-1,
1656 AXA_WHITESPACE))) {
1657 /* allow "ssh " for upward compatibility with old sratool */
1658 addr += sizeof(AXA_IO_TYPE_SSH_STR)-1 + i;
1659 result = AXA_IO_TYPE_SSH;
1660
1661 } else if (AXA_CLITCMP(addr, AXA_IO_TYPE_APIKEY_STR":")) {
1662 addr += sizeof(AXA_IO_TYPE_APIKEY_STR":")-1;
1663 result = AXA_IO_TYPE_APIKEY;
1664
1665 } else {
1666 return (AXA_IO_TYPE_UNKN);
1667 }
1668
1669 *addrp = addr;
1670 return (result);
1671 }
1672
1673 /* I/O type to string */
1674 const char *
axa_io_type_to_str(axa_io_type_t type)1675 axa_io_type_to_str(axa_io_type_t type)
1676 {
1677 switch (type) {
1678 case AXA_IO_TYPE_UNKN:
1679 default:
1680 return ("?");
1681 case AXA_IO_TYPE_UNIX:
1682 return (AXA_IO_TYPE_UNIX_STR);
1683 case AXA_IO_TYPE_TCP:
1684 return (AXA_IO_TYPE_TCP_STR);
1685 case AXA_IO_TYPE_SSH:
1686 return (AXA_IO_TYPE_SSH_STR);
1687 case AXA_IO_TYPE_TLS:
1688 return (AXA_IO_TYPE_TLS_STR);
1689 case AXA_IO_TYPE_APIKEY:
1690 return (AXA_IO_TYPE_APIKEY_STR);
1691 }
1692 }
1693
1694 void
axa_io_init(axa_io_t * io)1695 axa_io_init(axa_io_t *io)
1696 {
1697 memset(io, 0, sizeof(*io));
1698 io->su.sa.sa_family = -1;
1699 io->i_fd = -1;
1700 io->o_fd = -1;
1701 io->tun_fd = -1;
1702 io->tun_pid = -1;
1703 io->pvers = AXA_P_PVERS;
1704 }
1705
1706 void
axa_io_pvers_set(axa_io_t * io,uint8_t pvers)1707 axa_io_pvers_set(axa_io_t *io, uint8_t pvers)
1708 {
1709 AXA_ASSERT(io != NULL);
1710 io->pvers = pvers;
1711 }
1712
1713 void
axa_io_pvers_get(axa_io_t * io,uint8_t * pvers)1714 axa_io_pvers_get(axa_io_t *io, uint8_t *pvers)
1715 {
1716 AXA_ASSERT(io != NULL);
1717 *pvers = io->pvers;
1718 }
1719
1720 void
axa_recv_flush(axa_io_t * io)1721 axa_recv_flush(axa_io_t *io)
1722 {
1723 if (io->recv_body != NULL) {
1724 free(io->recv_body);
1725 io->recv_body = NULL;
1726 }
1727 io->recv_body_len = 0;
1728 }
1729
1730 static void
ck_close(int fd,const char * label)1731 ck_close(int fd, const char *label)
1732 {
1733 if (0 > close(fd)) {
1734 /* This should not happen. */
1735 axa_trace_msg("close(%s): %s", label, strerror(errno));
1736 }
1737 }
1738
1739 void
axa_io_close(axa_io_t * io)1740 axa_io_close(axa_io_t *io)
1741 {
1742 int wstatus;
1743
1744 switch (io->type) {
1745 case AXA_IO_TYPE_APIKEY:
1746 axa_apikey_stop(io);
1747 break;
1748 case AXA_IO_TYPE_TLS:
1749 axa_tls_stop(io);
1750 break;
1751 case AXA_IO_TYPE_UNIX:
1752 case AXA_IO_TYPE_UNKN:
1753 case AXA_IO_TYPE_SSH:
1754 case AXA_IO_TYPE_TCP:
1755 default:
1756 break;
1757 }
1758
1759 if (io->i_fd >= 0 && io->i_fd != io->o_fd)
1760 ck_close(io->i_fd, "io->i_fd");
1761 if (io->o_fd >= 0)
1762 ck_close(io->o_fd, "io->o_fd");
1763
1764 if (io->tun_fd >= 0)
1765 ck_close(io->tun_fd, "io->tun_fd");
1766
1767 if (io->tun_pid != -1) {
1768 kill(io->tun_pid, SIGKILL);
1769 waitpid(io->tun_pid, &wstatus, 0);
1770 }
1771
1772 axa_recv_flush(io);
1773 if (io->recv_buf != NULL)
1774 free(io->recv_buf);
1775
1776 if (io->tun_buf != NULL)
1777 free(io->tun_buf);
1778
1779 if (io->send_buf != NULL)
1780 free(io->send_buf);
1781
1782 if (io->addr != NULL)
1783 free(io->addr);
1784 if (io->label != NULL)
1785 free(io->label);
1786
1787 if (io->cert_file != NULL)
1788 free(io->cert_file);
1789 if (io->key_file != NULL)
1790 free(io->key_file);
1791 if (io->tls_info != NULL)
1792 free(io->tls_info);
1793
1794 /* Clear the FDs, PID, buffer pointers, etc. */
1795 axa_io_init(io);
1796 }
1797
1798 static axa_p_direction_t
which_direction(const axa_io_t * io,bool send)1799 which_direction(const axa_io_t *io, bool send)
1800 {
1801 bool to_srvr;
1802 axa_p_direction_t result;
1803
1804 to_srvr = ((send && io->is_client)
1805 || (!send && !io->is_client));
1806 if (io->is_rad) {
1807 result = to_srvr ? AXA_P_TO_RAD : AXA_P_FROM_RAD;
1808 } else {
1809 result = to_srvr ? AXA_P_TO_SRA : AXA_P_FROM_SRA;
1810 }
1811
1812 return (result);
1813 }
1814
1815 /* Make an error message for a bad AXA message header that looks like
1816 * an SSH message of the day.. */
1817 static void
motd_hdr(axa_emsg_t * emsg,axa_io_t * io)1818 motd_hdr(axa_emsg_t *emsg, axa_io_t *io)
1819 {
1820 ssize_t i;
1821
1822 if (io->type != AXA_IO_TYPE_SSH)
1823 return;
1824
1825 /* Did we receive the header in a single read? */
1826 if (io->recv_start != &io->recv_buf[sizeof(axa_p_hdr_t)]) {
1827 /* No, so do not disturb the existing error message. */
1828 return;
1829 }
1830
1831 /* Yes, so find the first non-ASCII byte. */
1832 for (i = 0; i < io->recv_bytes; ++i) {
1833 if (io->recv_start[i] < ' '
1834 || io->recv_start[i] > '~')
1835 break;
1836 }
1837
1838 /* Assume it is a message of the day via SSH if
1839 * there is a bunch of ASCII ending with '\n' or '\r'. */
1840 if (i == io->recv_bytes
1841 && (io->recv_start[i] == '\n'
1842 || io->recv_start[i] != '\r'))
1843 axa_pemsg(emsg, "unexpected text \"%.*s\" from %s",
1844 (int)i, io->recv_buf, io->label);
1845 }
1846
1847 axa_io_result_t
axa_recv_buf(axa_emsg_t * emsg,axa_io_t * io)1848 axa_recv_buf(axa_emsg_t *emsg, axa_io_t *io)
1849 {
1850 #define BUF_SIZE (64*1024)
1851 ssize_t len, i;
1852 size_t hdr_len;
1853 uint8_t *tgt;
1854 axa_io_result_t io_result;
1855
1856 /* Create unprocessed data buffer the first time. */
1857 if (io->recv_buf == NULL) {
1858 io->recv_buf_len = BUF_SIZE;
1859 io->recv_buf = axa_malloc(io->recv_buf_len);
1860 io->recv_bytes = 0;
1861 }
1862
1863 if (io->recv_body_len == 0)
1864 memset(&io->recv_hdr, 0, sizeof(io->recv_hdr));
1865
1866 for (;;) {
1867 /* Decide how many more bytes we need. */
1868 len = sizeof(io->recv_hdr) - io->recv_body_len;
1869 if (len > 0) {
1870 /* We do not yet have the entire header,
1871 * and so we must not have a place for the body. */
1872 AXA_ASSERT(io->recv_body == NULL);
1873
1874 tgt = (uint8_t *)&io->recv_hdr + io->recv_body_len;
1875
1876 } else {
1877 /* We have at least all of the header.
1878 * Check the header when we first have it. */
1879 if (len == 0
1880 && !axa_ck_hdr(emsg, &io->recv_hdr, io->label,
1881 which_direction(io, false))) {
1882 motd_hdr(emsg, io);
1883 return (AXA_IO_ERR);
1884 }
1885
1886 /* Stop when we have a complete message. */
1887 hdr_len = AXA_P2H32(io->recv_hdr.len);
1888 if (hdr_len == io->recv_body_len) {
1889 if (!axa_ck_body(emsg, io->recv_hdr.op,
1890 io->recv_body,
1891 hdr_len-sizeof(io->recv_hdr)))
1892 return (AXA_IO_ERR);
1893 return (AXA_IO_OK);
1894 }
1895
1896 /* Allocate the body only when needed. */
1897 if (io->recv_body == NULL)
1898 io->recv_body = axa_malloc(hdr_len
1899 - sizeof(io->recv_hdr));
1900 len = hdr_len - io->recv_body_len;
1901 tgt = ((uint8_t *)io->recv_body
1902 + io->recv_body_len - sizeof(io->recv_hdr));
1903 }
1904
1905 /* Read more data into the hidden buffer when we run out. */
1906 if (io->recv_bytes == 0) {
1907 io->recv_start = io->recv_buf;
1908 if (io->type == AXA_IO_TYPE_TLS ||
1909 io->type == AXA_IO_TYPE_APIKEY) {
1910 io_result = axa_tls_read(emsg, io);
1911 if (io_result != AXA_IO_OK)
1912 return (io_result);
1913 } else {
1914 for (;;) {
1915 i = read(io->i_fd, io->recv_buf,
1916 io->recv_buf_len);
1917 if (i > 0) {
1918 io->recv_bytes = i;
1919 gettimeofday(&io->alive, NULL);
1920 break;
1921 }
1922
1923 if (i == 0) {
1924 axa_pemsg(emsg, "read(%s): EOF",
1925 io->label);
1926 return (AXA_IO_ERR);
1927 }
1928 if (errno == EINTR)
1929 continue;
1930 if (errno == EAGAIN
1931 || errno == EWOULDBLOCK)
1932 return (AXA_IO_BUSY);
1933 axa_pemsg(emsg, "read(%s): %s",
1934 io->label, strerror(errno));
1935 return (AXA_IO_ERR);
1936 }
1937 }
1938 }
1939
1940 /* Consume data in the buffer. */
1941 i = min(len, io->recv_bytes);
1942 memcpy(tgt, io->recv_start, i);
1943 io->recv_start += i;
1944 io->recv_bytes -= i;
1945
1946 io->recv_body_len += i;
1947 }
1948 }
1949
1950 /* Wait for something to to happen */
1951 axa_io_result_t
axa_io_wait(axa_emsg_t * emsg,axa_io_t * io,time_t wait_ms,bool keepalive,bool tun)1952 axa_io_wait(axa_emsg_t *emsg, axa_io_t *io,
1953 time_t wait_ms, bool keepalive, bool tun)
1954 {
1955 struct timeval now;
1956 time_t ms;
1957 struct pollfd pollfds[3];
1958 int nfds, i_nfd, o_nfd, tun_nfd;
1959 int i;
1960
1961 /* Stop waiting when it is time for a keepalive. */
1962 if (keepalive) {
1963 gettimeofday(&now, NULL);
1964 ms = (AXA_KEEPALIVE_MS - axa_elapsed_ms(&now, &io->alive));
1965 if (wait_ms > ms)
1966 wait_ms = ms;
1967 }
1968 if (wait_ms < 0)
1969 wait_ms = 0;
1970
1971 memset(pollfds, 0, sizeof(pollfds));
1972 i_nfd = -1;
1973 o_nfd = -1;
1974 tun_nfd = -1;
1975 nfds = 0;
1976
1977 if (io->i_fd >= 0 && io->i_events != 0) {
1978 pollfds[nfds].fd = io->i_fd;
1979 pollfds[nfds].events = io->i_events;
1980 i_nfd = nfds++;
1981 }
1982
1983 if (io->o_fd >= 0 && io->o_events != 0) {
1984 pollfds[nfds].fd = io->o_fd;
1985 pollfds[nfds].events = io->o_events;
1986 o_nfd = nfds++;
1987 }
1988
1989 /* Watch the stderr pipe from a tunnel such as ssh. */
1990 if (tun && io->tun_fd >= 0) {
1991 pollfds[nfds].fd = io->tun_fd;
1992 pollfds[nfds].events = AXA_POLL_IN;
1993 tun_nfd = nfds++;
1994 }
1995
1996 i = poll(pollfds, nfds, wait_ms);
1997 if (i < 0 && errno != EINTR) {
1998 axa_pemsg(emsg, "poll(): %s", strerror(errno));
1999 return (AXA_IO_ERR);
2000 }
2001 if (i <= 0)
2002 return (AXA_IO_BUSY);
2003
2004 if (tun_nfd >= 0 && pollfds[tun_nfd].revents != 0)
2005 return (AXA_IO_TUNERR);
2006
2007 if ((i_nfd >= 0 && pollfds[i_nfd].revents != 0)
2008 || (o_nfd >= 0 && pollfds[o_nfd].revents != 0))
2009 return (AXA_IO_OK);
2010
2011 if (keepalive) {
2012 gettimeofday(&now, NULL);
2013 ms = (AXA_KEEPALIVE_MS - axa_elapsed_ms(&now, &io->alive));
2014 if (ms <= 0)
2015 return (AXA_IO_KEEPALIVE);
2016 }
2017 return (AXA_IO_BUSY);
2018 }
2019
2020 /* Wait for and read a complete AXA message from the server into
2021 * the client buffer. */
2022 axa_io_result_t
axa_input(axa_emsg_t * emsg,axa_io_t * io,time_t wait_ms)2023 axa_input(axa_emsg_t *emsg, axa_io_t *io, time_t wait_ms)
2024 {
2025 axa_io_result_t result;
2026
2027 for (;;) {
2028 if (!AXA_IO_OPENED(io)) {
2029 axa_pemsg(emsg, "not open");
2030 return (AXA_IO_ERR);
2031 }
2032 if (!AXA_IO_CONNECTED(io)) {
2033 axa_pemsg(emsg, "not connected");
2034 return (AXA_IO_ERR);
2035 }
2036
2037 /* Read more from the peer when needed. */
2038 if (io->recv_buf == NULL || io->recv_bytes == 0) {
2039 result = axa_io_wait(emsg, io, wait_ms,
2040 AXA_IO_CONNECTED(io), true);
2041 switch (result) {
2042 case AXA_IO_OK:
2043 break;
2044 case AXA_IO_ERR:
2045 case AXA_IO_TUNERR:
2046 case AXA_IO_KEEPALIVE:
2047 case AXA_IO_BUSY:
2048 return (result);
2049 }
2050 }
2051
2052 result = axa_recv_buf(emsg, io);
2053 switch (result) {
2054 case AXA_IO_OK:
2055 case AXA_IO_ERR:
2056 return (result);
2057 case AXA_IO_BUSY:
2058 continue; /* wait for the rest */
2059 case AXA_IO_TUNERR: /* impossible */
2060 case AXA_IO_KEEPALIVE: /* impossible */
2061 AXA_FAIL("impossible axa_recv_buf() result");
2062 }
2063 }
2064 }
2065
2066 size_t
axa_make_hdr(axa_emsg_t * emsg,axa_p_hdr_t * hdr,axa_p_pvers_t pvers,axa_tag_t tag,axa_p_op_t op,size_t b1_len,size_t b2_len,axa_p_direction_t dir)2067 axa_make_hdr(axa_emsg_t *emsg, axa_p_hdr_t *hdr,
2068 axa_p_pvers_t pvers, axa_tag_t tag, axa_p_op_t op,
2069 size_t b1_len, size_t b2_len, axa_p_direction_t dir)
2070 {
2071 size_t total;
2072
2073 memset(hdr, 0, sizeof(axa_p_hdr_t));
2074 hdr->tag = AXA_H2P_TAG(tag);
2075 total = sizeof(*hdr) + b1_len + b2_len;
2076 hdr->len = AXA_H2P32(total);
2077 hdr->pvers = pvers;
2078 hdr->op = op;
2079
2080 if (!axa_ck_hdr(emsg, hdr, "myself", dir))
2081 return (0);
2082
2083 return (total);
2084 }
2085
2086 /* Send an AXA request or response to the server or client.
2087 * The message is in 0, 1, 2, or 3 parts.
2088 * hdr is the optional AXA protocol header to be built
2089 * b1 and b1_len specify an optional second part after the header
2090 * b2 and b2_len specify the third part. */
2091 axa_io_result_t
axa_send(axa_emsg_t * emsg,axa_io_t * io,axa_tag_t tag,axa_p_op_t op,axa_p_hdr_t * hdr,const void * b1,size_t b1_len,const void * b2,size_t b2_len)2092 axa_send(axa_emsg_t *emsg, axa_io_t *io,
2093 axa_tag_t tag, axa_p_op_t op, axa_p_hdr_t *hdr,
2094 const void *b1, size_t b1_len,
2095 const void *b2, size_t b2_len)
2096 {
2097 axa_p_hdr_t hdr0;
2098 struct iovec iov[3];
2099 int iovcnt;
2100 ssize_t total, done;
2101
2102 if (hdr == NULL)
2103 hdr = &hdr0;
2104 total = axa_make_hdr(emsg, hdr, io->pvers, tag, op,
2105 b1_len, b2_len, which_direction(io, true));
2106 if (total == 0)
2107 return (AXA_IO_ERR);
2108
2109 if (io->type == AXA_IO_TYPE_TLS || io->type == AXA_IO_TYPE_APIKEY) {
2110 /*
2111 * For TLS, save all 3 parts in the overflow output buffer
2112 * so that the AXA message can be sent as a single TLS
2113 * transaction. This is expensive, but only if you ignore
2114 * the cost of TLS encryption.
2115 */
2116 axa_send_save(io, 0, hdr, b1, b1_len, b2, b2_len);
2117 return (axa_tls_flush(emsg, io));
2118 }
2119
2120 for (;;) {
2121 iov[0].iov_base = hdr;
2122 iov[0].iov_len = sizeof(*hdr);
2123 if (b1_len == 0) {
2124 iovcnt = 1;
2125 } else {
2126 iov[1].iov_base = (void *)b1;
2127 iov[1].iov_len = b1_len;
2128 if (b2_len == 0) {
2129 iovcnt = 2;
2130 } else {
2131 iov[2].iov_base = (void *)b2;
2132 iov[2].iov_len = b2_len;
2133 iovcnt = 3;
2134 }
2135 }
2136
2137 done = writev(io->o_fd, iov, iovcnt);
2138 if (done > 0) {
2139 gettimeofday(&io->alive, NULL);
2140 break;
2141 }
2142
2143 if (done < 0) {
2144 if (errno == EINTR) {
2145 /* ignore signals */
2146 continue;
2147 }
2148 if (errno == EAGAIN || errno == EWOULDBLOCK) {
2149 /* None sent, so give up and let
2150 * the caller save or discard. */
2151 return (AXA_IO_BUSY);
2152 }
2153
2154 axa_pemsg(emsg, "writev(%s): %s",
2155 io->label, strerror(errno));
2156 return (AXA_IO_ERR);
2157 }
2158 }
2159 if (done < total)
2160 axa_send_save(io, done, hdr, b1, b1_len, b2, b2_len);
2161
2162 return (AXA_IO_OK);
2163 }
2164
2165 /* Add to the buffer of pending output data. */
2166 void
axa_send_save(axa_io_t * io,size_t done,const axa_p_hdr_t * hdr,const void * b1,size_t b1_len,const void * b2,size_t b2_len)2167 axa_send_save(axa_io_t *io, size_t done, const axa_p_hdr_t *hdr,
2168 const void *b1, size_t b1_len,
2169 const void *b2, size_t b2_len)
2170 {
2171 ssize_t avail_len, new_len;
2172 ssize_t undone, chunk;
2173 uint8_t *new_buf, *p;
2174
2175 undone = sizeof(*hdr)+b1_len+b2_len - done;
2176 AXA_ASSERT(undone > 0);
2177
2178 /* Expand the buffer if necessary */
2179 avail_len = io->send_buf_len - io->send_bytes;
2180 if (avail_len < undone) {
2181 new_len = (io->send_buf_len + undone + 1024 + 1023) & ~1024;
2182 new_buf = axa_malloc(new_len);
2183
2184 /* Save previously saved data. */
2185 if (io->send_buf != NULL) {
2186 if (io->send_bytes != 0)
2187 memcpy(new_buf, io->send_start, io->send_bytes);
2188 free(io->send_buf);
2189 }
2190 io->send_buf = new_buf;;
2191 io->send_start = io->send_buf;
2192 io->send_buf_len = new_len;
2193
2194 } else if (avail_len - (io->send_start - io->send_buf) < undone) {
2195 /* slide down previously pending data */
2196 if (io->send_bytes != 0)
2197 memmove(io->send_buf, io->send_start, io->send_bytes);
2198 io->send_start = io->send_buf;
2199 }
2200
2201 /* Copy the unsent parts of the header and two chucks of body */
2202 p = io->send_start + io->send_bytes;
2203 io->send_bytes += undone;
2204
2205 chunk = sizeof(*hdr) - done;
2206 if (chunk > 0) {
2207 /* Some or all of the header was not sent.
2208 * Save the unsent part. */
2209 memcpy(p, (uint8_t *)hdr + done, chunk);
2210 p += chunk;
2211 done += chunk;
2212 }
2213
2214 chunk = sizeof(*hdr)+b1_len - done;
2215 if (chunk > 0) {
2216 /* Some or all of the first chunk of body was not sent.
2217 * Save the unsent part. */
2218 memcpy(p, ((uint8_t *)b1)+(b1_len-chunk), chunk);
2219 p += chunk;
2220 done += chunk;
2221 }
2222
2223 chunk = sizeof(*hdr)+b1_len+b2_len - done;
2224 if (chunk > 0) {
2225 /* Some or all of the second chunk of body was not sent.
2226 * Save the unsent part. */
2227 memcpy(p, ((uint8_t *)b2)+(b2_len-chunk), chunk);
2228 }
2229 }
2230
2231 /* Flush pending output */
2232 axa_io_result_t
axa_send_flush(axa_emsg_t * emsg,axa_io_t * io)2233 axa_send_flush(axa_emsg_t *emsg, axa_io_t *io)
2234 {
2235 ssize_t done;
2236
2237 if (io->type == AXA_IO_TYPE_TLS || io->type == AXA_IO_TYPE_APIKEY)
2238 return (axa_tls_flush(emsg, io));
2239
2240 /* Repeat other transports until nothing flows. */
2241 for (;;) {
2242 if (io->send_bytes == 0) {
2243 io->o_events = 0;
2244 return (AXA_IO_OK);
2245 }
2246
2247 done = write(io->o_fd, io->send_start,
2248 io->send_bytes);
2249 if (done < 0) {
2250 if (errno != EAGAIN && errno != EWOULDBLOCK) {
2251 io->send_bytes = 0;
2252 axa_pemsg(emsg, "send(): %s",
2253 strerror(errno));
2254 return (AXA_IO_ERR);
2255 }
2256
2257 io->o_events = AXA_POLL_OUT;
2258 return (AXA_IO_BUSY);
2259 }
2260 io->send_start += done;
2261 io->send_bytes -= done;
2262
2263 gettimeofday(&io->alive, NULL);
2264 }
2265 }
2266
2267 /* Capture anything that the tunnel (eg. ssh) process says. */
2268 const char * /* NULL or \'0' terminated string */
axa_io_tunerr(axa_io_t * io)2269 axa_io_tunerr(axa_io_t *io)
2270 {
2271 int i;
2272 char *p;
2273
2274 /* Create the buffer the first time */
2275 if (io->tun_buf == NULL || io->tun_buf_size == 0) {
2276 AXA_ASSERT(io->tun_buf == NULL && io->tun_buf_size == 0);
2277 io->tun_buf_size = 120;
2278 io->tun_buf = axa_malloc(io->tun_buf_size);
2279 }
2280
2281 for (;;) {
2282 /* Discard the previously returned line. */
2283 if (io->tun_buf_bol != 0) {
2284 i = io->tun_buf_len - io->tun_buf_bol;
2285 if (i > 0)
2286 memmove(io->tun_buf,
2287 &io->tun_buf[io->tun_buf_bol],
2288 i);
2289 io->tun_buf_len -= io->tun_buf_bol;
2290 io->tun_buf_bol = 0;
2291 }
2292
2293 /* Hope to return the next line in the buffer. */
2294 if (io->tun_buf_len > 0) {
2295 i = min(io->tun_buf_len, io->tun_buf_size);
2296 p = memchr(io->tun_buf, '\n', i);
2297 if (p != NULL) {
2298 *p = '\0';
2299 io->tun_buf_bol = p+1 - io->tun_buf;
2300
2301 /* trim '\r' */
2302 while (p > io->tun_buf && *--p == '\r')
2303 *p = '\0';
2304 /* Discard blank lines. */
2305 if (p == io->tun_buf)
2306 continue;
2307 return (io->tun_buf);
2308 }
2309 }
2310
2311 /* Get more data, possibly completing a partial line. */
2312 i = io->tun_buf_size-1 - io->tun_buf_len;
2313 if (i > 0 && io->tun_fd >= 0) {
2314 i = read(io->tun_fd,
2315 &io->tun_buf[io->tun_buf_len],
2316 i);
2317
2318 /* Return the 1st line in the new buffer load */
2319 if (i > 0) {
2320 io->tun_buf_len += i;
2321 io->tun_buf[io->tun_buf_len] = '\0';
2322 continue;
2323 }
2324
2325 if (i < 0
2326 && errno != EWOULDBLOCK && errno != EAGAIN) {
2327 /* Return error message at errors. */
2328 snprintf(io->tun_buf, io->tun_buf_size,
2329 "read(tunerr): %s",
2330 strerror(errno));
2331 io->tun_buf_len = strlen(io->tun_buf)+1;
2332 close(io->tun_fd);
2333 io->tun_fd = -1;
2334
2335 } else if (i == 0) {
2336 close(io->tun_fd);
2337 io->tun_fd = -1;
2338 }
2339 }
2340
2341 /* Return whatever we have. */
2342 io->tun_buf_bol = io->tun_buf_len;
2343 return ((io->tun_buf_len > 0) ? io->tun_buf : NULL);
2344 }
2345 }
2346
2347 /* Clean up AXA I/O functions including freeing TLS data */
2348 void
axa_io_cleanup(void)2349 axa_io_cleanup(void)
2350 {
2351 axa_tls_cleanup();
2352 axa_apikey_cleanup();
2353 }
2354