1 /*
2 ** Copyright (C) 2001-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8
9 /*
10 ** sku-string.c
11 **
12 ** A collection of utility routines to manipulate strings
13 **
14 */
15
16 #include <silk/silk.h>
17
18 RCSIDENT("$SiLK: sku-string.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
19
20 #include <silk/utils.h>
21 #include <silk/skipaddr.h>
22 #include <silk/skvector.h>
23 #include <silk/rwrec.h>
24
25 #ifndef USE_GETADDRINFO
26 # ifdef SK_HAVE_GETADDRINFO
27 # define USE_GETADDRINFO 1
28 # else
29 # define USE_GETADDRINFO 0
30 # endif
31 #endif
32 #if !USE_GETADDRINFO && SK_ENABLE_INET6_NETWORKING
33 # undef SK_ENABLE_INET6_NETWORKING
34 # define SK_ENABLE_INET6_NETWORKING 0
35 #endif
36
37
38 #define STRING_PARSE_MIN_YEAR 1970
39 #define STRING_PARSE_MAX_YEAR 2039
40 #define STRING_PARSE_MIN_EPOCH (1 << 29) /* Mon Jan 5 18:48:32 1987 */
41 #define STRING_PARSE_MAX_EPOCH ((1u << 31)-1) /* Tue Jan 19 03:14:07 2038 */
42
43
44 static const struct signal_name2num_st {
45 const char *name;
46 int number;
47 } signal_name2num[] = {
48 #ifdef SIGABRT
49 {"ABRT", SIGABRT},
50 #endif
51 #ifdef SIGALRM
52 {"ALRM", SIGALRM},
53 #endif
54 #ifdef SIGBUS
55 {"BUS", SIGBUS},
56 #endif
57 #ifdef SIGCANCEL
58 {"CANCEL", SIGCANCEL},
59 #endif
60 #ifdef SIGCHLD
61 {"CHLD", SIGCHLD},
62 #endif
63 #ifdef SIGCLD
64 {"CLD", SIGCLD},
65 #endif
66 #ifdef SIGCONT
67 {"CONT", SIGCONT},
68 #endif
69 #ifdef SIGEMT
70 {"EMT", SIGEMT},
71 #endif
72 #ifdef SIGEXIT
73 {"EXIT", SIGEXIT},
74 #endif
75 #ifdef SIGFPE
76 {"FPE", SIGFPE},
77 #endif
78 #ifdef SIGFREEZE
79 {"FREEZE", SIGFREEZE},
80 #endif
81 #ifdef SIGHUP
82 {"HUP", SIGHUP},
83 #endif
84 #ifdef SIGILL
85 {"ILL", SIGILL},
86 #endif
87 #ifdef SIGINFO
88 {"INFO", SIGINFO},
89 #endif
90 #ifdef SIGINT
91 {"INT", SIGINT},
92 #endif
93 #ifdef SIGIO
94 {"IO", SIGIO},
95 #endif
96 #ifdef SIGIOT
97 {"IOT", SIGIOT},
98 #endif
99 #ifdef SIGKILL
100 {"KILL", SIGKILL},
101 #endif
102 #ifdef SIGLOST
103 {"LOST", SIGLOST},
104 #endif
105 #ifdef SIGPIPE
106 {"PIPE", SIGPIPE},
107 #endif
108 #ifdef SIGPOLL
109 {"POLL", SIGPOLL},
110 #endif
111 #ifdef SIGPROF
112 {"PROF", SIGPROF},
113 #endif
114 #ifdef SIGPWR
115 {"PWR", SIGPWR},
116 #endif
117 #ifdef SIGQUIT
118 {"QUIT", SIGQUIT},
119 #endif
120 #ifdef SIGSEGV
121 {"SEGV", SIGSEGV},
122 #endif
123 #ifdef SIGSTKFLT
124 {"STKFLT", SIGSTKFLT},
125 #endif
126 #ifdef SIGSTOP
127 {"STOP", SIGSTOP},
128 #endif
129 #ifdef SIGSYS
130 {"SYS", SIGSYS},
131 #endif
132 #ifdef SIGTERM
133 {"TERM", SIGTERM},
134 #endif
135 #ifdef SIGTHAW
136 {"THAW", SIGTHAW},
137 #endif
138 #ifdef SIGTRAP
139 {"TRAP", SIGTRAP},
140 #endif
141 #ifdef SIGTSTP
142 {"TSTP", SIGTSTP},
143 #endif
144 #ifdef SIGTTIN
145 {"TTIN", SIGTTIN},
146 #endif
147 #ifdef SIGTTOU
148 {"TTOU", SIGTTOU},
149 #endif
150 #ifdef SIGUNUSED
151 {"UNUSED", SIGUNUSED},
152 #endif
153 #ifdef SIGURG
154 {"URG", SIGURG},
155 #endif
156 #ifdef SIGUSR1
157 {"USR1", SIGUSR1},
158 #endif
159 #ifdef SIGUSR2
160 {"USR2", SIGUSR2},
161 #endif
162 #ifdef SIGVTALRM
163 {"VTALRM", SIGVTALRM},
164 #endif
165 #ifdef SIGWAITING
166 {"WAITING", SIGWAITING},
167 #endif
168 #ifdef SIGWINCH
169 {"WINCH", SIGWINCH},
170 #endif
171 #ifdef SIGXCPU
172 {"XCPU", SIGXCPU},
173 #endif
174 #ifdef SIGXFSZ
175 {"XFSZ", SIGXFSZ},
176 #endif
177 #ifdef SIGXRES
178 {"XRES", SIGXRES},
179 #endif
180 {"", 0}
181 };
182
183 static const int signal_name2num_count =
184 ((sizeof(signal_name2num)/sizeof(struct signal_name2num_st)) - 1);
185
186
187 /* Structure used when parsing a comma-separated list of numbers and ranges */
188 typedef struct sk_number_parser_st {
189 const char *sp;
190 const char *end_chars;
191 int base;
192 uint32_t min;
193 uint32_t max;
194 } sk_number_parser_t;
195
196 /* Values used by numberListParser*() to indicate success. Error
197 * values are given by silk_utils_errcode_t. */
198 typedef enum {
199 /* Indicates numberListParserInit() initialized successfully */
200 SK_NUM_PARSER_OK = 0,
201
202 /* Indicates numberListParserNext() parsed a single number and
203 * an optional trailing comma, e.g. "3" or "5," */
204 SK_NUM_PARSER_NUMBER,
205
206 /* Indicates numberListParserNext() parsed a range and an
207 * optional trailing comma, e.g., "3-4" or "5-6," */
208 SK_NUM_PARSER_RANGE,
209
210 /* Indicates numberListParserNext() parsed an open-ended range
211 * and an optional trailing comma, e.g., "3-" or "5-,". Ranges
212 * with open-beginnings (e.g., "-7") are not allowed. */
213 SK_NUM_PARSER_RANGE_OPENMAX,
214
215 /* Indicates numberListParserInit() or
216 * numberListParserNext() reached the end of the number list;
217 * that is, current character is NUL, or whitespace, or a
218 * character specified in the end_chars. */
219 SK_NUM_PARSER_END_OF_STRING
220 } sk_number_parser_result_t;
221
222
223 /*
224 * pos = numberParserCurrentChar(p);
225 *
226 * Returns the beginning of the token that the parser was parsing
227 * when it encountered the error.
228 */
229 #define numberParserCurrentChar(parser) ((parser)->sp)
230
231
232 /*
233 * The following macros, variables, and functions are used to set
234 * error messages encountered when parsing something, and they work
235 * with the silk_utils_errcode_t enumeration defined in utils.h.
236 *
237 * The parseError() function stores an error message in the
238 * parse_error_buf[] array, where we maintain the most recent error
239 * for each error code.
240 *
241 * The caller can access the messages in the array with the
242 * skStringParseStrerror() function.
243 */
244
245 /* this should be same magnitude as the last error code specified in
246 * silk_utils_errcode_t */
247 #define PARSE_ERRORCODE_COUNT ((silk_utils_errcode_t)13)
248
249 /* convert silk_utils_errcode_t 'errcode' to a positive index used to
250 * index into parse_error_buf[] and parse_error_default[]. Value with
251 * largest magnitude becomes 0; the "succcess" value of 0 becomes
252 * PARSE_ERRORCODE_COUNT. */
253 #define PARSE_ERRORCODE_TO_INDEX(errcode) \
254 (((errcode) < -PARSE_ERRORCODE_COUNT) \
255 ? (-1) \
256 : ((errcode) + PARSE_ERRORCODE_COUNT))
257
258 /* return default error message for silk_utils_errcode_t 'errcode' */
259 #define PARSE_ERRORCODE_MSG(errcode) \
260 (((errcode) < -PARSE_ERRORCODE_COUNT || (errcode) > 0) \
261 ? "" \
262 : parse_error_default[PARSE_ERRORCODE_TO_INDEX(errcode)])
263
264 /* hold the most recent error for each silk_utils_errcode_t */
265 static char parse_error_buf[PARSE_ERRORCODE_COUNT+1][2048];
266
267 /* these are in reverse order of how they appear in the definition of
268 * silk_utils_errcode_t */
269 static const char *parse_error_default[PARSE_ERRORCODE_COUNT+1] = {
270 "Could not resolve hostname or port", /* SKUTILS_ERR_RESOLVE */
271 "Value is above maximum", /* SKUTILS_ERR_MAXIMUM */
272 "Value is below minimum", /* SKUTILS_ERR_MINIMUM */
273 "Miscellaneous error", /* SKUTILS_ERR_OTHER */
274 "Out of memory", /* SKUTILS_ERR_ALLOC */
275 "Too many fields provided", /* SKUTILS_ERR_TOO_MANY_FIELDS */
276 "Unexpected end-of-input", /* SKUTILS_ERR_SHORT */
277 "Range is invalid (min > max)", /* SKUTILS_ERR_BAD_RANGE */
278 "Value underflows the parser", /* SKUTILS_ERR_UNDERFLOW */
279 "Value overflows the parser", /* SKUTILS_ERR_OVERFLOW */
280 "Unexpected character", /* SKUTILS_ERR_BAD_CHAR */
281 "Input is empty or all whitespace", /* SKUTILS_ERR_EMPTY */
282 "Invalid input to function", /* SKUTILS_ERR_INVALID */
283 "Command successful" /* SKUTILS_OK */
284 };
285
286
287 #ifdef TEST_PRINTF_FORMATS
288 # define parseError(errcode, ...) printf(__VA_ARGS__)
289 # define PE_NULL "ERROR"
290 #else
291 # define PE_NULL NULL
292 static int
293 parseError(
294 silk_utils_errcode_t errcode,
295 const char *fmt,
296 ...)
297 SK_CHECK_PRINTF(2, 3);
298
299 static int
parseError(silk_utils_errcode_t errcode,const char * fmt,...)300 parseError(
301 silk_utils_errcode_t errcode,
302 const char *fmt,
303 ...)
304 {
305 va_list args;
306 int idx;
307 char *buf;
308
309 idx = PARSE_ERRORCODE_TO_INDEX(errcode);
310
311 if (idx < 0 || idx > PARSE_ERRORCODE_COUNT) {
312 return errcode;
313 }
314 buf = parse_error_buf[idx];
315
316 if (fmt == PE_NULL) {
317 snprintf(buf, sizeof(parse_error_buf[0]), "%s",
318 parse_error_default[idx]);
319 buf[sizeof(parse_error_buf[0])-1] = '\0';
320 return errcode;
321 }
322
323 va_start(args, fmt);
324 vsnprintf(buf, sizeof(parse_error_buf[0]), fmt, args);
325 buf[sizeof(parse_error_buf[0])-1] = '\0';
326 va_end(args);
327 return errcode;
328 }
329 #endif /* TEST_PRINTF_FORMATS */
330
331
332 const char *
skStringParseStrerror(int errorcode)333 skStringParseStrerror(
334 int errorcode)
335 {
336 static char tmpbuf[2048];
337 int idx = PARSE_ERRORCODE_TO_INDEX(errorcode);
338
339 if (errorcode > 0) {
340 return "Extra text follows value";
341 }
342 if (idx < 0 || idx > PARSE_ERRORCODE_COUNT) {
343 snprintf(tmpbuf, sizeof(tmpbuf), "Unrecognized error (%d)", errorcode);
344 tmpbuf[sizeof(tmpbuf)-1] = '\0';
345 return tmpbuf;
346 }
347
348 return parse_error_buf[idx];
349 }
350
351
352 /* Convert integer 0 to string "0.0.0.0"; uses static buffer */
353 char *
num2dot(uint32_t ip)354 num2dot(
355 uint32_t ip)
356 {
357 static char outbuf[SKIPADDR_STRLEN];
358 skipaddr_t ipaddr;
359
360 skipaddrSetV4(&ipaddr, &ip);
361 return skipaddrString(outbuf, &ipaddr, SKIPADDR_CANONICAL);
362 }
363
364
365 /* Convert integer 0 to string "0.0.0.0"; uses caller's buffer */
366 char *
num2dot_r(uint32_t ip,char * outbuf)367 num2dot_r(
368 uint32_t ip,
369 char *outbuf)
370 {
371 skipaddr_t ipaddr;
372
373 skipaddrSetV4(&ipaddr, &ip);
374 return skipaddrString(outbuf, &ipaddr, SKIPADDR_CANONICAL);
375 }
376
377
378 /* Convert integer 0 to string "000.000.000.000"; uses static buffer */
379 char *
num2dot0(uint32_t ip)380 num2dot0(
381 uint32_t ip)
382 {
383 static char outbuf[SKIPADDR_STRLEN];
384 skipaddr_t ipaddr;
385
386 skipaddrSetV4(&ipaddr, &ip);
387 return skipaddrString(outbuf, &ipaddr,
388 SKIPADDR_CANONICAL | SKIPADDR_ZEROPAD);
389 }
390
391
392 /* Convert integer 0 to string "000.000.000.000"; uses caller's buffer */
393 char *
num2dot0_r(uint32_t ip,char * outbuf)394 num2dot0_r(
395 uint32_t ip,
396 char *outbuf)
397 {
398 skipaddr_t ipaddr;
399
400 skipaddrSetV4(&ipaddr, &ip);
401 return skipaddrString(outbuf, &ipaddr,
402 SKIPADDR_CANONICAL | SKIPADDR_ZEROPAD);
403 }
404
405
406 /* Convert integer to FSRPAUEC string. Uses caller's buffer. */
407 char *
skTCPFlagsString(uint8_t flags,char * outbuf,unsigned int print_flags)408 skTCPFlagsString(
409 uint8_t flags,
410 char *outbuf,
411 unsigned int print_flags)
412 {
413 static const char characters[] = {'F', 'S', 'R', 'P', 'A', 'U', 'E', 'C'};
414 static const uint8_t bits[] = {FIN_FLAG, SYN_FLAG, RST_FLAG, PSH_FLAG,
415 ACK_FLAG, URG_FLAG, ECE_FLAG, CWR_FLAG};
416 int i;
417 char *c = outbuf;
418
419 for (i = 0; i < 8; i++) {
420 if (flags & bits[i]) {
421 *c = characters[i];
422 ++c;
423 } else if (print_flags & SK_PADDED_FLAGS) {
424 *c = ' ';
425 ++c;
426 }
427 }
428 *c = '\0';
429 return outbuf;
430 }
431
432 /* Deprecated */
433 char *
tcpflags_string_r(uint8_t flags,char * outbuf)434 tcpflags_string_r(
435 uint8_t flags,
436 char *outbuf)
437 {
438 return skTCPFlagsString(flags, outbuf, SK_PADDED_FLAGS);
439 }
440
441 /* Deprecated */
442 char *
tcpflags_string(uint8_t flags)443 tcpflags_string(
444 uint8_t flags)
445 {
446 static char flag_string[SK_TCPFLAGS_STRLEN];
447 return skTCPFlagsString(flags, flag_string, SK_PADDED_FLAGS);
448 }
449
450
451 /* Convert integer to TCP state string. Uses caller's buffer. */
452 char *
skTCPStateString(uint8_t state,char * outbuf,unsigned int print_flags)453 skTCPStateString(
454 uint8_t state,
455 char *outbuf,
456 unsigned int print_flags)
457 {
458 #define SKTCPSTATE_NUM_BITS 4
459 static const char characters[] = {'T', 'C', 'F', 'S'};
460 static const uint8_t bits[] = {SK_TCPSTATE_TIMEOUT_KILLED,
461 SK_TCPSTATE_TIMEOUT_STARTED,
462 SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK,
463 SK_TCPSTATE_UNIFORM_PACKET_SIZE};
464 int i;
465 char *c = outbuf;
466
467 for (i = 0; i < SKTCPSTATE_NUM_BITS; i++) {
468 if (state & bits[i]) {
469 *c = characters[i];
470 ++c;
471 } else if (print_flags & SK_PADDED_FLAGS) {
472 *c = ' ';
473 ++c;
474 }
475 }
476 if (print_flags & SK_PADDED_FLAGS) {
477 for (/*empty*/; i < 8; i++) {
478 *c = ' ';
479 ++c;
480 }
481 }
482 *c = '\0';
483 return outbuf;
484 }
485
486
487 /* strip whitespace of line in-place; return length */
488 int
skStrip(char * line)489 skStrip(
490 char *line)
491 {
492 char *sp, *ep;
493 int len;
494
495 sp = line;
496 while ( *sp && isspace((int)*sp) ) {
497 sp++;
498 }
499 /* at first non-space char OR at end of line */
500 if (*sp == '\0') {
501 /* line full of white space. nail at beginning and return with 0 */
502 line[0] = '\0';
503 return 0;
504 }
505
506 /* figure out where to stop the line */
507 ep = sp + strlen(sp) - 1;
508 while ( isspace((int)*ep) && (ep > sp) ) {
509 ep--;
510 }
511 /* ep at last non-space char. Nail after */
512 ep++;
513 *ep = '\0';
514
515 len = (int)(ep - sp);
516 if (sp == line) {
517 /* no shifting required */
518 return(len);
519 }
520
521 memmove(line, sp, len+1);
522 return(len);
523 }
524
525
526 /* Down-case 'cp' in place */
527 void
skToLower(char * cp)528 skToLower(
529 char *cp)
530 {
531 while (*cp) {
532 if (isupper((int)*cp)) {
533 *cp = *cp + 32;
534 }
535 cp++;
536 }
537 return;
538 }
539
540
541 /* Up-case 'cp' in place */
542 void
skToUpper(char * cp)543 skToUpper(
544 char *cp)
545 {
546 while (*cp) {
547 if (islower((int)*cp)) {
548 *cp = *cp - 32;
549 }
550 cp++;
551 }
552 return;
553 }
554
555
556 /*
557 * result = numberListParserInit(&p,input,base,end_chars,minimum,maximum);
558 *
559 * Fills in the sk_number_parser_t data structure---which should
560 * have been declared and allocated by the caller---pointed at by
561 * 'p' with state necessary to call numberListParserNext().
562 *
563 * The caller must not modify 'input' while the
564 * numberListParserNext() function is in use.
565 *
566 * 'end_chars' should be NULL or a string listing characters to be
567 * considered, in addition to whitespace, as end-of-input markers.
568 *
569 * 'mimimum' and 'maximum' define the allowable range for numbers
570 * in the list.
571 *
572 * On success, SK_NUM_PARSER_OK is returned. If the string is
573 * empty or begins with a character listed in 'end_chars',
574 * SK_NUM_PARSER_END_OF_STRING is returned. Otherwise, this
575 * function returns a silk_utils_errcode_t value.
576 */
577 static int
numberListParserInit(sk_number_parser_t * parser,const char * input,int base,const char * end_chars,uint32_t minimum,uint32_t maximum)578 numberListParserInit(
579 sk_number_parser_t *parser,
580 const char *input,
581 int base,
582 const char *end_chars,
583 uint32_t minimum,
584 uint32_t maximum)
585 {
586 /* check input */
587 assert(parser);
588 assert(input);
589 assert(base == 10 || base == 16);
590
591 if (maximum == 0) {
592 maximum = UINT32_MAX;
593 } else if (minimum > maximum) {
594 return parseError(SKUTILS_ERR_INVALID,
595 ("Range maximum (%" PRIu32 ") is less than"
596 " range minimum (%" PRIu32 ")"),
597 maximum, minimum);
598 }
599
600 if (*input == '\0') {
601 return SK_NUM_PARSER_END_OF_STRING;
602 }
603 if (isspace((int)*input)) {
604 return SK_NUM_PARSER_END_OF_STRING;
605 }
606 if (end_chars && (strchr(end_chars, *input))) {
607 return SK_NUM_PARSER_END_OF_STRING;
608 }
609
610 if (base == 10 && !isdigit((int)*input)) {
611 return parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
612 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *input);
613 } else if (base == 16 && !isxdigit((int)*input)) {
614 return parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
615 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *input);
616 }
617
618 parser->min = minimum;
619 parser->max = maximum;
620 parser->sp = input;
621 parser->end_chars = end_chars;
622 parser->base = base;
623 return SK_NUM_PARSER_OK;
624 }
625
626
627 /*
628 * result = numberListParserNext(&out_val, &out_length, p);
629 *
630 * Parse the next number or range in the 'input' that was used to
631 * initialize the sk_number_parser_t 'p'.
632 *
633 * If the next token is a single number ("3,"), its value is stored
634 * in 'out_val', 1 is stored in 'out_length', and
635 * SK_NUM_PARSER_NUMBER is returned.
636 *
637 * If the next token is a range ("2-4,"), the starting value (2) is
638 * stored in 'out_val', the number of elements in the range (3) is
639 * stored in 'out_length', and SK_NUM_PARSER_RANGE is returned.
640 *
641 * When there are no more tokens in 'input',
642 * SK_NUM_PARSER_END_OF_STRING is returned.
643 *
644 * Any other return value indicates an error.
645 */
646 static int
numberListParserNext(uint64_t * range_length,uint32_t * value,sk_number_parser_t * parser)647 numberListParserNext(
648 uint64_t *range_length,
649 uint32_t *value,
650 sk_number_parser_t *parser)
651 {
652 unsigned long n = 0;
653 const char *sp;
654 char *ep;
655 int rv;
656
657 /* check input */
658 assert(parser);
659 assert(value);
660 assert(range_length);
661
662 /* initialize vars */
663 *value = 0;
664 *range_length = 0;
665 sp = parser->sp;
666
667 /* are we at end of list? */
668 if (*sp == '\0') {
669 return SK_NUM_PARSER_END_OF_STRING;
670 }
671 if (isspace((int)*sp)) {
672 return SK_NUM_PARSER_END_OF_STRING;
673 }
674 if (parser->end_chars && (strchr(parser->end_chars, *sp))) {
675 return SK_NUM_PARSER_END_OF_STRING;
676 }
677
678 while (*sp) {
679 /* parse the number */
680 errno = 0;
681 n = strtoul(sp, &ep, parser->base);
682 if (sp == ep) {
683 rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
684 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
685 goto END;
686 }
687 if (n == ULONG_MAX && errno == ERANGE) {
688 rv = parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
689 goto END;
690 }
691 if (n < parser->min) {
692 rv = parseError(SKUTILS_ERR_MINIMUM, "%s of %" PRIu32,
693 PARSE_ERRORCODE_MSG(SKUTILS_ERR_MINIMUM),
694 parser->min);
695 goto END;
696 }
697 if (n > parser->max) {
698 rv = parseError(SKUTILS_ERR_MAXIMUM, "%s of %" PRIu32,
699 PARSE_ERRORCODE_MSG(SKUTILS_ERR_MAXIMUM),
700 parser->max);
701 goto END;
702 }
703
704 /* parsed the number; move pointer to next token */
705 sp = ep;
706
707 /* see if we are parsing a range; if so, store the first
708 * number (lower limit) and loop through the while again in
709 * order to parse the second number (upper limit). */
710 if (*sp != '-') {
711 break;
712 } else if (*range_length != 0) {
713 /* second pass through the while loop yet we're looking at
714 * another hyphen. We've got something like "1-2-". An
715 * error */
716 rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
717 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
718 goto END;
719 } else {
720 /* first pass, we just parsed lower limit */
721 ++sp;
722 if ((parser->base == 10 && isdigit((int)*sp))
723 || (parser->base == 16 && isxdigit((int)*sp)))
724 {
725 /* looks like a good range; store the value we just
726 * parsed, set range_length so we know we're in a
727 * range, and loop again */
728 *value = n;
729 *range_length = 1;
730 continue;
731 } else if (*sp == '\0' || *sp == ',') {
732 /* open-ended range, store current value, use
733 * range_length to denote open-ended range, set n to
734 * the max */
735 *value = n;
736 *range_length = 2;
737 n = parser->max;
738 break;
739 } else {
740 rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
741 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
742 *sp);
743 goto END;
744 }
745 }
746 }
747
748 /* we've parsed a number or a range */
749 if (*range_length == 0) {
750 /* single number */
751 *value = n;
752 *range_length = 1;
753 rv = SK_NUM_PARSER_NUMBER;
754 } else if (*range_length == 2) {
755 *range_length = (n - *value + 1);
756 rv = SK_NUM_PARSER_RANGE_OPENMAX;
757 } else if (n == *value) {
758 /* range of 3-3; treat as single number */
759 rv = SK_NUM_PARSER_NUMBER;
760 } else if (n < *value) {
761 rv = parseError(SKUTILS_ERR_BAD_RANGE,
762 ("%s (%" PRIu32 "-%lu)"),
763 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_RANGE),
764 *value, n);
765 goto END;
766 } else {
767 *range_length = (n - *value + 1);
768 rv = SK_NUM_PARSER_RANGE;
769 }
770
771 /* move forward to the start of the next number. */
772 while (*sp) {
773 if (isspace((int)*sp)) {
774 /* this marks the end of the number list */
775 break;
776 }
777 if (parser->end_chars && (strchr(parser->end_chars, *sp))) {
778 /* this also marks the end of the number list */
779 break;
780 }
781 if ((parser->base == 10 && isdigit((int)*sp))
782 || (parser->base == 16 && isxdigit((int)*sp)))
783 {
784 /* this is what we expect*/
785 break;
786 }
787 if (*sp == ',') {
788 /* duplicate comma is allowed */
789 ++sp;
790 continue;
791 }
792 if (*sp == '-') {
793 /* error */
794 rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
795 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
796 *sp);
797 goto END;
798 }
799
800 /* error */
801 rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
802 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
803 *sp);
804 goto END;
805 }
806
807 END:
808 /* store our current location */
809 parser->sp = sp;
810 return rv;
811 }
812
813
814 /* parse string "4,3,2-6" to array {4,3,2,3,4,5,6}. See header for details */
815 int
skStringParseNumberList(uint32_t ** number_list,uint32_t * number_count,const char * input,uint32_t min_value,uint32_t max_value,uint32_t max_number_count)816 skStringParseNumberList(
817 uint32_t **number_list,
818 uint32_t *number_count,
819 const char *input,
820 uint32_t min_value,
821 uint32_t max_value,
822 uint32_t max_number_count)
823 {
824 uint64_t range_length;
825 uint64_t i;
826 uint32_t range_start;
827 uint32_t *out_array_list = NULL; /* returned array */
828 uint32_t out_count = 0; /* returned count */
829 uint32_t array_size;
830 sk_number_parser_t parser;
831 const char *sp;
832 int rv = SKUTILS_OK;
833
834 /* check input */
835 assert(number_list);
836 assert(number_count);
837 if (input == NULL) {
838 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
839 }
840
841 /* eat leading whitespace */
842 sp = input;
843 while (*sp && isspace((int)*sp)) {
844 ++sp;
845 }
846 if ('\0' == *sp) {
847 /* whitespace only or empty string */
848 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
849 }
850
851 rv = numberListParserInit(&parser, sp, 10, NULL, min_value, max_value);
852 if (rv != SK_NUM_PARSER_OK) {
853 return rv;
854 }
855
856 /* If no max count was given, assume the user is only allowed to
857 * choose each item one time, and set the max_number_count to the
858 * number of items. */
859 if (max_number_count == 0) {
860 if (max_value != 0) {
861 max_number_count = 1 + max_value - min_value;
862 } else {
863 /* something big */
864 max_number_count = (1 << 24);
865 }
866 }
867
868 /* Create the array to hold the list of values. If
869 * max_number_count is greater than 256, use half of it as the
870 * initial size; otherwise, create an array of max_number_count
871 * entries. */
872 if (max_number_count <= 256) {
873 array_size = max_number_count;
874 } else {
875 array_size = max_number_count / 2;
876 }
877 out_array_list = (uint32_t*)calloc(array_size, sizeof(uint32_t));
878 if (!out_array_list) {
879 rv = parseError(SKUTILS_ERR_ALLOC, PE_NULL);
880 goto ERROR;
881 }
882
883 while ((rv = numberListParserNext(&range_length, &range_start, &parser))
884 != SK_NUM_PARSER_END_OF_STRING)
885 {
886 if (rv < 0) {
887 goto ERROR;
888 }
889 switch ((sk_number_parser_result_t)rv) {
890 case SK_NUM_PARSER_OK:
891 case SK_NUM_PARSER_END_OF_STRING:
892 /* these should not occur */
893 skAbortBadCase(rv);
894
895 case SK_NUM_PARSER_RANGE_OPENMAX:
896 rv = parseError(SKUTILS_ERR_BAD_CHAR,
897 ("Range is missing its upper limit"
898 " (open-ended ranges are not supported)"));
899 goto ERROR;
900
901 case SK_NUM_PARSER_NUMBER:
902 case SK_NUM_PARSER_RANGE:
903 /* check number of fields user gave */
904 if ((out_count + range_length) > max_number_count) {
905 rv = parseError(SKUTILS_ERR_TOO_MANY_FIELDS,
906 ("Too many fields (%" PRIu64 ") provided;"
907 " only %" PRIu32 " fields allowed"),
908 (range_length + out_count), max_number_count);
909 goto ERROR;
910 }
911
912 /* check if we need to grow array? If so, realloc the array
913 * to double its size and memset the new section to 0. */
914 while ((out_count + range_length) > array_size) {
915 size_t old_size = array_size;
916 uint32_t *old_array = out_array_list;
917 array_size *= 2;
918 if (array_size > max_number_count) {
919 array_size = max_number_count;
920 }
921 out_array_list = (uint32_t*)realloc(
922 out_array_list, array_size * sizeof(uint32_t));
923 if (!out_array_list) {
924 out_array_list = old_array;
925 rv = parseError(SKUTILS_ERR_ALLOC, PE_NULL);
926 goto ERROR;
927 }
928 memset((out_array_list+old_size), 0,
929 (array_size-old_size) * sizeof(uint32_t));
930 }
931
932 /* add the entries */
933 for (i = 0; i < range_length; ++i, ++range_start, ++out_count) {
934 out_array_list[out_count] = range_start;
935 }
936 break;
937 }
938 }
939
940 assert(rv == SK_NUM_PARSER_END_OF_STRING);
941 rv = SKUTILS_OK;
942
943 /* handle any whitespace at end of string */
944 sp = numberParserCurrentChar(&parser);
945 while (isspace((int)*sp)) {
946 ++sp;
947 }
948 if (*sp != '\0') {
949 rv = parseError(SKUTILS_ERR_BAD_CHAR,
950 "%s--embedded whitespace found in input",
951 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
952 goto ERROR;
953 }
954
955 *number_count = out_count;
956 *number_list = out_array_list;
957 return rv;
958
959 ERROR:
960 if (out_array_list) {
961 free(out_array_list);
962 }
963 *number_count = 0;
964 return rv;
965 }
966
967
968 /* parse string "4,3,2-6" to skbitmap. See header for details */
969 int
skStringParseNumberListToBitmap(sk_bitmap_t * out_bitmap,const char * input)970 skStringParseNumberListToBitmap(
971 sk_bitmap_t *out_bitmap,
972 const char *input)
973 {
974 uint64_t range_length;
975 uint64_t i;
976 uint32_t value;
977 uint32_t bitmap_size;
978 sk_number_parser_t parser;
979 const char *sp;
980 int rv;
981
982 memset(&parser, 0, sizeof(parser));
983
984 /* check input */
985 assert(out_bitmap);
986 if (input == NULL) {
987 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
988 }
989
990 /* check bitmap size */
991 bitmap_size = skBitmapGetSize(out_bitmap);
992 if (bitmap_size < 1) {
993 /* bitmap too small */
994 return parseError(SKUTILS_ERR_INVALID, "Bitmap is too small");
995 }
996
997 /* eat leading whitespace */
998 sp = input;
999 while (*sp && isspace((int)*sp)) {
1000 ++sp;
1001 }
1002 if ('\0' == *sp) {
1003 /* whitespace only or empty string */
1004 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
1005 }
1006
1007 rv = numberListParserInit(&parser, sp, 10, NULL, 0, bitmap_size-1);
1008 if (rv != SK_NUM_PARSER_OK) {
1009 return rv;
1010 }
1011
1012 while ((rv = numberListParserNext(&range_length, &value, &parser))
1013 != SK_NUM_PARSER_END_OF_STRING)
1014 {
1015 if (rv < 0) {
1016 return rv;
1017 }
1018 switch ((sk_number_parser_result_t)rv) {
1019 case SK_NUM_PARSER_NUMBER:
1020 case SK_NUM_PARSER_RANGE:
1021 case SK_NUM_PARSER_RANGE_OPENMAX:
1022 /* add the entries */
1023 for (i = 0; i < range_length; ++i, ++value) {
1024 skBitmapSetBit(out_bitmap, value);
1025 }
1026 break;
1027
1028 case SK_NUM_PARSER_OK:
1029 case SK_NUM_PARSER_END_OF_STRING:
1030 /* impossible */
1031 skAbortBadCase(rv);
1032 }
1033 }
1034
1035 assert(rv == SK_NUM_PARSER_END_OF_STRING);
1036
1037 /* handle any whitespace at end of string */
1038 sp = numberParserCurrentChar(&parser);
1039 while (isspace((int)*sp)) {
1040 ++sp;
1041 }
1042 if (*sp != '\0') {
1043 return parseError(SKUTILS_ERR_BAD_CHAR,
1044 "%s--embedded whitespace found in input",
1045 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1046 }
1047
1048 return SKUTILS_OK;
1049 }
1050
1051
1052 /*
1053 * status = parseIPv4(&ip_value, ip_string);
1054 *
1055 * A helper function for skStringParseIP().
1056 *
1057 * Parse the IPv4 address at 'ip_string' and put the result--in
1058 * native byte order--into the memory pointed at by 'ip_value'.
1059 * Return a negative (silk_utils_errcode_t) value on error;
1060 * otherwise return a positive value specifying the number of
1061 * characters that were parsed.
1062 */
1063 static int
parseIPv4(uint32_t * ip,const char * ip_string)1064 parseIPv4(
1065 uint32_t *ip,
1066 const char *ip_string)
1067 {
1068 unsigned long final = 0;
1069 unsigned long val;
1070 const char *sp = ip_string;
1071 char *ep;
1072 int i;
1073
1074 *ip = 0;
1075
1076 /* number that begins with '-' is not unsigned */
1077 if ('-' == *sp) {
1078 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1079 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1080 *sp);
1081 }
1082
1083 for (i = 3; i >= 0; --i) {
1084 /* parse the number */
1085 errno = 0;
1086 val = strtoul(sp, &ep, 10);
1087 if (sp == ep) {
1088 /* parse error */
1089 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1090 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
1091 }
1092 if (val == ULONG_MAX && errno == ERANGE) {
1093 /* overflow */
1094 if (i == 3) {
1095 /* entire value is too large */
1096 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
1097 }
1098 /* octet value is too large */
1099 return parseError(SKUTILS_ERR_OVERFLOW,
1100 "IP octet %d is too large", (4 - i));
1101 }
1102 if (val > UINT8_MAX) {
1103 if (i == 3 && *ep != '.') {
1104 /* treat as a single integer */
1105 #if (SK_SIZEOF_LONG > 4)
1106 if (val > UINT32_MAX) {
1107 return parseError(SKUTILS_ERR_MAXIMUM,
1108 "Integer too large for IPv4: %lu", val);
1109 }
1110 #endif
1111 sp = ep;
1112 final = val;
1113 break;
1114 }
1115 /* value too big for octet */
1116 return parseError(SKUTILS_ERR_MAXIMUM,
1117 "IP octet %d is too large: %lu", (4 - i), val);
1118 }
1119
1120 sp = ep;
1121 if (*sp != '.') {
1122 if (i == 3) {
1123 /* treat as a single integer */
1124 assert(val <= UINT8_MAX);
1125 final = val;
1126 break;
1127 }
1128 if (i != 0) {
1129 if (*sp == '\0') {
1130 return parseError(SKUTILS_ERR_SHORT, PE_NULL);
1131 }
1132 /* need a '.' between octets */
1133 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1134 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1135 *sp);
1136 }
1137 /* else i == 0 and we've finished parsing */
1138 } else if (i == 0) {
1139 /* found a trailing '.' */
1140 return parseError(SKUTILS_ERR_BAD_CHAR,
1141 "Found '%c' after fourth octet", *sp);
1142 } else {
1143 /* move to start of next octet */
1144 ++sp;
1145 if (!isdigit((int)*sp)) {
1146 /* error: only '.' and digits are allowed */
1147 if (*sp == '\0') {
1148 return parseError(SKUTILS_ERR_SHORT, PE_NULL);
1149 }
1150 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1151 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1152 *sp);
1153 }
1154 }
1155
1156 final |= val << (8 * i);
1157 }
1158
1159 *ip = (uint32_t)final;
1160 return (sp - ip_string);
1161 }
1162
1163 #if SK_ENABLE_IPV6
1164 /*
1165 * status = parseIPv6(&ipaddr, ip_string);
1166 *
1167 * A helper function for skStringParseIP().
1168 *
1169 * Parse the IPv6 address at 'ip_string' and put the result--in
1170 * native byte order--into the memory pointed at by 'ip_value'.
1171 * Return a negative (silk_utils_errcode_t) value on error;
1172 * otherwise return a positive value specifying the number of
1173 * characters that were parsed.
1174 */
1175 static int
parseIPv6(skipaddr_t * ipaddr,const char * ip_string)1176 parseIPv6(
1177 skipaddr_t *ipaddr,
1178 const char *ip_string)
1179 {
1180 uint8_t ipv6[16];
1181 unsigned int double_colon = UINT_MAX;
1182 unsigned long val;
1183 unsigned int i;
1184 const char *sp = ip_string;
1185 char *ep;
1186
1187 /* handle a "::" at the start of the address */
1188 if (':' == *sp) {
1189 if (':' != *(sp + 1)) {
1190 /* address cannot begin with single ':' */
1191 return parseError(SKUTILS_ERR_BAD_CHAR,
1192 "IP address cannot begin with single ':'");
1193 }
1194 if (':' == *(sp + 2)) {
1195 /* triple colon */
1196 return parseError(SKUTILS_ERR_BAD_CHAR,
1197 "Unexpected character :::");
1198 }
1199 double_colon = 0;
1200 sp += 2;
1201 }
1202
1203 for (i = 0; i < 8; ++i) {
1204 /* expecting a base-16 number */
1205 if (!isxdigit((int)*sp)) {
1206 if (double_colon != UINT_MAX) {
1207 /* treat as end of string */
1208 break;
1209 }
1210 if (*sp == '\0') {
1211 return parseError(SKUTILS_ERR_SHORT,
1212 "Too few IP sections given");
1213 }
1214 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1215 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1216 *sp);
1217 }
1218
1219 /* parse the number */
1220 errno = 0;
1221 val = strtoul(sp, &ep, 16);
1222 if (sp == ep) {
1223 if (double_colon != UINT_MAX) {
1224 /* treat as end of string */
1225 break;
1226 }
1227 /* parse error */
1228 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1229 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1230 *sp);
1231 }
1232 if (val == ULONG_MAX && errno == ERANGE) {
1233 /* overflow */
1234 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
1235 }
1236 if (val > UINT16_MAX) {
1237 /* value too big for octet */
1238 return parseError(SKUTILS_ERR_MAXIMUM,
1239 "Value in IP section %u is too large",
1240 i + 1);
1241 }
1242
1243 /* if a dot follows the number we just parsed, treat that
1244 * number as the start of an embedded IPv4 address. */
1245 if (*ep == '.') {
1246 unsigned int j;
1247 uint32_t ipv4;
1248 int rv;
1249
1250 if (i > 6) {
1251 return parseError(SKUTILS_ERR_BAD_CHAR,
1252 ("Too many sections before"
1253 " embedded IPv4"));
1254 }
1255 /* IPv4 address */
1256 rv = parseIPv4(&ipv4, sp);
1257 if (rv < 0) {
1258 return rv;
1259 }
1260
1261 for (j = 0; j < 4; ++j) {
1262 ipv6[2*i+j] = ((ipv4 >> (8 * (3 - j))) & 0xFF);
1263 }
1264 sp += rv;
1265 i += 2;
1266 if (*sp == ':') {
1267 /* Must not have more IPv6 after the IPv4 addr */
1268 return parseError(SKUTILS_ERR_BAD_CHAR,
1269 "Found '%c' after final section", *sp);
1270 }
1271 break;
1272 }
1273
1274 ipv6[2*i] = ((val >> 8) & 0xFF);
1275 ipv6[2*i+1] = (val & 0xFF);
1276 sp = ep;
1277
1278 /* handle section separator */
1279 if (*sp != ':') {
1280 if (i != 7) {
1281 if (double_colon != UINT_MAX) {
1282 /* treat as end of string */
1283 ++i;
1284 break;
1285 }
1286 if (*sp == '\0') {
1287 return parseError(SKUTILS_ERR_SHORT,
1288 "Too few IP sections given");
1289 }
1290 /* need a ':' between sections */
1291 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1292 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1293 *sp);
1294 }
1295 /* else i == 7 and we've finished parsing */
1296 } else if (i == 7) {
1297 return parseError(SKUTILS_ERR_BAD_CHAR,
1298 "Found '%c' after final section", *sp);
1299 } else {
1300 /* move to start of next section */
1301 ++sp;
1302 if (':' == *sp) {
1303 if (double_colon != UINT_MAX) {
1304 /* parse error */
1305 return parseError(SKUTILS_ERR_BAD_CHAR,
1306 "Only one :: instance allowed");
1307 }
1308 if (':' == *(sp + 1)) {
1309 /* triple colon */
1310 return parseError(SKUTILS_ERR_BAD_CHAR,
1311 "Unexpected character :::");
1312 }
1313 double_colon = i + 1;
1314 ++sp;
1315 } else if (*sp == '\0') {
1316 return parseError(SKUTILS_ERR_SHORT,
1317 "Expecting IP section value after ':'");
1318 } else if (!isxdigit((int)*sp)) {
1319 /* number must follow lone ':' */
1320 return
1321 parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1322 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1323 *sp);
1324 }
1325 }
1326 }
1327
1328 if (double_colon != UINT_MAX) {
1329 if (i == 8) {
1330 /* error */
1331 return parseError(SKUTILS_ERR_BAD_CHAR,
1332 "Cannot have '::' in IP with 8 sections");
1333 }
1334 memmove(&ipv6[2*(8+double_colon-i)], &ipv6[2*double_colon],
1335 2*(i-double_colon));
1336 memset(&ipv6[2*double_colon], 0, 2*(8-i));
1337 } else if (i != 8) {
1338 /* error */
1339 return parseError(SKUTILS_ERR_SHORT,
1340 "Only %u/8 IP sections specified", i);
1341 }
1342
1343 skipaddrSetV6(ipaddr, ipv6);
1344 return (sp - ip_string);
1345 }
1346 #endif /* SK_ENABLE_IPV6 */
1347
1348 /* Parse a string as an IPv4 or IPv6 address. If the string is a
1349 * single integer, treat is an an IPv4 address. */
1350 int
skStringParseIP(skipaddr_t * out_val,const char * ip_string)1351 skStringParseIP(
1352 skipaddr_t *out_val,
1353 const char *ip_string)
1354 {
1355 const char *sp;
1356 const char *dot;
1357 const char *colon;
1358 int rv;
1359
1360 /* verify input */
1361 if (!ip_string) {
1362 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
1363 }
1364
1365 /* skip leading whitespace */
1366 sp = ip_string;
1367 while (isspace((int)*sp)) {
1368 ++sp;
1369 }
1370 if ('\0' == *sp) {
1371 /* whitespace only or empty string */
1372 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
1373 }
1374
1375 /* determine if IPv4 or IPv6 */
1376 dot = strchr(sp, '.');
1377 colon = strchr(sp, ':');
1378 if (colon == NULL) {
1379 /* no ':', so must be IPv4 or an integer */
1380 } else if (dot == NULL) {
1381 /* no '.', so must be IPv6 */
1382 } else if ((dot - sp) < (colon - sp)) {
1383 /* dot appears first, assume IPv4 */
1384 colon = NULL;
1385 } else {
1386 /* colon appears first, assume IPv6 */
1387 dot = NULL;
1388 }
1389
1390 /* parse the address */
1391 if (NULL == colon) {
1392 /* an IPv4 address */
1393 uint32_t ipv4;
1394
1395 rv = parseIPv4(&ipv4, sp);
1396 if (rv < 0) {
1397 return rv;
1398 }
1399 skipaddrSetV4(out_val, &ipv4);
1400 } else
1401 #if SK_ENABLE_IPV6
1402 {
1403 /* an IPv6 address */
1404 rv = parseIPv6(out_val, sp);
1405 if (rv < 0) {
1406 return rv;
1407 }
1408 }
1409 #else /* SK_ENABLE_IPV6 */
1410 {
1411 /* an IPv6 address but no IPv6 support */
1412 return parseError(SKUTILS_ERR_BAD_CHAR,
1413 "%s ':'--IPv6 addresses not supported",
1414 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1415 }
1416 #endif /* #else of #if SK_ENABLE_IPV6 */
1417
1418 sp += rv;
1419
1420 /* ignore trailing whitespace, but only if we reach the end of the
1421 * string. cache the current position. */
1422 rv = (sp - ip_string);
1423 while (isspace((int)*sp)) {
1424 ++sp;
1425 }
1426
1427 if ('\0' != *sp) {
1428 /* text after IP, return the cached position */
1429 return rv;
1430 }
1431 return SKUTILS_OK;
1432 }
1433
1434
1435 int
skStringParseIPWildcard(skIPWildcard_t * ipwild,const char * ip_string)1436 skStringParseIPWildcard(
1437 skIPWildcard_t *ipwild,
1438 const char *ip_string)
1439 {
1440 /* number of octets (or hexadectets for IPv6) */
1441 uint32_t num_blocks = 4;
1442 /* number of bits per octet/hexadectet */
1443 uint32_t block_size = 8;
1444 /* max value for any octet/hexadectet */
1445 uint32_t block_max_value = ((1 << block_size) - 1);
1446 /* base to use for parsing octet/hexadectet values */
1447 int block_base;
1448 /* character string between octets/hexadectets */
1449 const char *block_sep;
1450 uint64_t i;
1451 uint32_t range_start = 0;
1452 uint64_t range_length = 0;
1453 unsigned long val = 0;
1454 uint32_t block = 0;
1455 uint32_t double_colon = UINT32_MAX;
1456 sk_number_parser_t parser;
1457 skipaddr_t ipaddr;
1458 uint32_t cidr = 0;
1459 const char *sp;
1460 int rv;
1461 #if SK_ENABLE_IPV6
1462 const char *v4_in_v6 = NULL;
1463 #endif
1464
1465 /* try to parse as an ordinary IP address */
1466 rv = skStringParseIP(&ipaddr, ip_string);
1467
1468 /* return if we get any error other than BAD_CHAR */
1469 if (rv < 0 && rv != SKUTILS_ERR_BAD_CHAR) {
1470 return rv;
1471 }
1472
1473 /* If rv > 0, we parsed an IP but there is extra text. We could
1474 * be looking at the slash for CIDR notation or at a list for the
1475 * final block; e.g., "0.0.0.1-100" or "0.0.0.1,2". If we are on
1476 * the slash, reset rv to SKUTILS_OK; otherwise, if we are looking
1477 * at anything other than ',' or '-', return error. For IPv6, we
1478 * may be looking at "0::x". */
1479 if (rv > 0) {
1480 sp = &ip_string[rv];
1481 if (*sp == '/') {
1482 ++sp;
1483 if (*sp == '\0') {
1484 return parseError(SKUTILS_ERR_BAD_CHAR,
1485 "%s '%c'--expected CIDR after slash",
1486 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1487 *sp);
1488 }
1489 if (!isdigit((int)*sp)) {
1490 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1491 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1492 *sp);
1493 }
1494
1495 /* parse the CIDR value */
1496 rv = skStringParseUint32(&cidr, sp, 1,
1497 (skipaddrIsV6(&ipaddr) ? 128 : 32));
1498 if (rv != 0) {
1499 if (rv < 0) {
1500 return rv;
1501 }
1502 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1503 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1504 sp[rv]);
1505 }
1506 } else if (isspace((int)*sp)) {
1507 return parseError(SKUTILS_ERR_BAD_CHAR,
1508 "%s '%c' embedded whitespace is not allowed",
1509 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1510 *sp);
1511 #if SK_ENABLE_IPV6
1512 } else if (skipaddrIsV6(&ipaddr) && (*sp == 'x' || *sp == 'X')) {
1513 /* try to parse as wildcard */
1514 #endif /* SK_ENABLE_IPV6 */
1515 } else if (*sp != '-' && *sp != ',') {
1516 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1517 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1518 *sp);
1519 }
1520 }
1521
1522 /* clear the ipwildcard */
1523 skIPWildcardClear(ipwild);
1524
1525 if (rv == SKUTILS_OK) {
1526 #if SK_ENABLE_IPV6
1527 if (skipaddrIsV6(&ipaddr)) {
1528 uint8_t ip6[16];
1529
1530 skipaddrGetV6(&ipaddr, &ip6);
1531 ipwild->num_blocks = 8;
1532
1533 num_blocks = 8;
1534 block_size = 16;
1535 block_max_value = (1 << block_size) - 1;
1536
1537 /* set each block as if no CIDR */
1538 for (block = 0; block < num_blocks; ++block) {
1539 val = (ip6[2*block] << 8 | ip6[1+2*block]);
1540 ipwild->m_blocks[block][_BMAP_INDEX(val)] = _BMAP_OFFSET(val);
1541 ipwild->m_min[block] = val;
1542 ipwild->m_max[block] = val;
1543 }
1544 } else
1545 #endif /* SK_ENABLE_IPV6 */
1546 {
1547 ipwild->num_blocks = 4;
1548
1549 /* set each block as if no CIDR */
1550 for (block = 0; block < num_blocks; ++block) {
1551 val = (block_max_value
1552 & (skipaddrGetV4(&ipaddr)
1553 >> ((num_blocks - block - 1) * block_size)));
1554 ipwild->m_blocks[block][_BMAP_INDEX(val)] = _BMAP_OFFSET(val);
1555 ipwild->m_min[block] = val;
1556 ipwild->m_max[block] = val;
1557 }
1558 }
1559
1560 if (cidr == 0 || cidr == (num_blocks * block_size)) {
1561 return SKUTILS_OK;
1562 }
1563
1564 for (block = 0; block < num_blocks; ++block) {
1565 if (cidr <= (block_size * block)) {
1566 /* this block is all ones */
1567 memset(ipwild->m_blocks[block], 0xFF,
1568 sizeof(ipwild->m_blocks[0]));
1569 ipwild->m_min[block] = 0;
1570 ipwild->m_max[block] = block_max_value;
1571 } else if (cidr < (block_size * (1 + block))) {
1572 /* partial effect on this block */
1573 range_length = 1 << ((block_size * (1 + block)) - cidr);
1574 val = (ipwild->m_min[block] & ~(range_length - 1));
1575 ipwild->m_min[block] = val;
1576 for (i = 0; i < range_length; ++i, ++val) {
1577 ipwild->m_blocks[block][_BMAP_INDEX(val)]
1578 |= _BMAP_OFFSET(val);
1579 }
1580 ipwild->m_max[block] = val - 1;
1581 }
1582 /* else (cidr >= (block_size*(1+block))) and no effect */
1583 }
1584 return SKUTILS_OK;
1585 }
1586
1587 /* Parse the input ip from the beginning */
1588 sp = ip_string;
1589
1590 /* ignore leading whitespace */
1591 while (isspace((int)*sp)) {
1592 ++sp;
1593 }
1594
1595 if (strchr(sp, ':')) {
1596 #if !SK_ENABLE_IPV6
1597 return parseError(SKUTILS_ERR_BAD_CHAR,
1598 "%s '%c'--IPv6 addresses not supported",
1599 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1600 *sp);
1601 #else
1602 ipwild->num_blocks = 8;
1603 block_sep = ":";
1604 num_blocks = 8;
1605 block_size = 16;
1606 block_base = 16;
1607
1608 /* check for a v4 section, for example "::ffff:x.x.x.x". if
1609 * we find a '.', move backward to find the ':' and as
1610 * v4_in_v6 to the character following the ':'. */
1611 v4_in_v6 = strchr(sp, '.');
1612 if (v4_in_v6) {
1613 while (v4_in_v6 > sp) {
1614 if (*(v4_in_v6 - 1) == ':') {
1615 break;
1616 }
1617 --v4_in_v6;
1618 }
1619 if (v4_in_v6 == sp) {
1620 /* must have something with ':' following '.' */
1621 return parseError(SKUTILS_ERR_BAD_CHAR,
1622 "Found ':' after '.' in IPv6 address");
1623 }
1624 }
1625 #endif /* SK_ENABLE_IPV6 */
1626 } else {
1627 block_sep = ".";
1628 ipwild->num_blocks = 4;
1629 num_blocks = 4;
1630 block_size = 8;
1631 block_base = 10;
1632 }
1633 block_max_value = (1 << block_size) - 1;
1634
1635 for (block = 0; block < num_blocks; ++block) {
1636 if (*sp == ':') {
1637 ++sp;
1638 if (*sp == ':') {
1639 if (double_colon != UINT32_MAX) {
1640 /* parse error */
1641 return parseError(SKUTILS_ERR_BAD_CHAR,
1642 "Only one :: instance allowed");
1643 }
1644 ++sp;
1645 double_colon = block;
1646 } else if (block == 0) {
1647 /* address cannot begin with single ':' */
1648 return parseError(SKUTILS_ERR_BAD_CHAR,
1649 "IP address cannot begin with single ':'");
1650 } else if (*sp == '\0') {
1651 return parseError(SKUTILS_ERR_SHORT,
1652 "Expecting IP block value after ':'");
1653 }
1654 } else if (*sp == '.') {
1655 assert(block_base == 10);
1656 if (block == 0) {
1657 return parseError(SKUTILS_ERR_BAD_CHAR,
1658 "%s--found leading separator '%c'",
1659 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1660 *sp);
1661 }
1662 ++sp;
1663 } else if (*sp == '\0') {
1664 if (double_colon != UINT32_MAX) {
1665 /* treat as end of the IP */
1666 break;
1667 }
1668 return parseError(SKUTILS_ERR_SHORT,
1669 "Too few IP blocks given");
1670 } else if (block != 0) {
1671 return parseError(SKUTILS_ERR_BAD_CHAR,
1672 "%s '%c' expecting '%s' between IP blocks",
1673 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp,
1674 block_sep);
1675 }
1676
1677 #if SK_ENABLE_IPV6
1678 /* determine if we are at beginning of an embedded IPv4 address */
1679 if (sp == v4_in_v6) {
1680 skIPWildcard_t ipwv4;
1681 uint32_t j, k;
1682
1683 /* verify we don't have too many IPv6 sections */
1684 if (block > 6) {
1685 return parseError(SKUTILS_ERR_BAD_CHAR,
1686 "Too many sections before embedded IPv4");
1687 }
1688
1689 /* parse the remaining part of the address as IPv4 wildcard */
1690 rv = skStringParseIPWildcard(&ipwv4, sp);
1691 if (rv < 0) {
1692 return rv;
1693 }
1694
1695 /* move sp to the end of the string */
1696 sp += strlen(sp);
1697
1698 /* take the ipv4 wildcard and map it into ipv6 */
1699 for (i = 0; i < 4; i += 2, ++block) {
1700 ipwild->m_min[block] = (ipwv4.m_min[i]<<8) | ipwv4.m_min[i+1];
1701 ipwild->m_max[block] = (ipwv4.m_max[i]<<8) | ipwv4.m_max[i+1];
1702
1703 /* shortcut the "x.x" case */
1704 if ((ipwild->m_min[block] == 0)
1705 && (ipwild->m_min[block] == 0xFFFF))
1706 {
1707 memset(ipwild->m_blocks[block], 0xFF,
1708 sizeof(ipwild->m_blocks[0]));
1709 if (memcmp(ipwild->m_blocks[block],
1710 ipwv4.m_blocks[i],
1711 sizeof(ipwild->m_blocks[0]))
1712 && memcmp(ipwild->m_blocks[block],
1713 ipwv4.m_blocks[i+1],
1714 sizeof(ipwild->m_blocks[0])))
1715 {
1716 continue;
1717 } else {
1718 memset(ipwild->m_blocks[block], 0,
1719 sizeof(ipwild->m_blocks[0]));
1720 }
1721 }
1722
1723 for (j = ipwv4.m_min[i]; j <= ipwv4.m_max[i]; ++j) {
1724 for (k = ipwv4.m_min[i+1]; k <= ipwv4.m_max[i+1]; ++k) {
1725 if (_IPWILD_BLOCK_IS_SET(&ipwv4, i, j)
1726 && _IPWILD_BLOCK_IS_SET(&ipwv4, i+1, k))
1727 {
1728 ipwild->m_blocks[block][_BMAP_INDEX((j << 8) | k)]
1729 |= _BMAP_OFFSET((j << 8) | k);
1730 }
1731 }
1732 }
1733 }
1734
1735 /* done */
1736 break;
1737 }
1738 #endif /* SK_ENABLE_IPV6 */
1739
1740 if (*sp == 'x' || *sp == 'X') {
1741 /* all ones */
1742 memset(ipwild->m_blocks[block], 0xFF, sizeof(ipwild->m_blocks[0]));
1743 ipwild->m_min[block] = 0;
1744 ipwild->m_max[block] = block_max_value;
1745 ++sp;
1746 continue;
1747 }
1748
1749 rv = numberListParserInit(&parser, sp, block_base, block_sep,
1750 0, block_max_value);
1751 if (rv != SK_NUM_PARSER_OK) {
1752 if (rv != SK_NUM_PARSER_END_OF_STRING) {
1753 return rv;
1754 }
1755 if (*sp == *block_sep) {
1756 return parseError(SKUTILS_ERR_BAD_CHAR,
1757 "%s--found double '%c'",
1758 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1759 *sp);
1760 }
1761 if (double_colon == block) {
1762 /* treat as end of string */
1763 break;
1764 }
1765 if (isspace((int)*sp)) {
1766 return parseError(SKUTILS_ERR_BAD_CHAR,
1767 "%s--embedded whitespace found in input",
1768 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1769 }
1770 return parseError(SKUTILS_ERR_SHORT, "Too few blocks given");
1771 }
1772
1773 while ((rv = numberListParserNext(&range_length, &range_start,&parser))
1774 != SK_NUM_PARSER_END_OF_STRING)
1775 {
1776 switch (rv) {
1777 case SK_NUM_PARSER_OK:
1778 /* this should not occur */
1779 skAbortBadCase(rv);
1780
1781 case SK_NUM_PARSER_RANGE_OPENMAX:
1782 return parseError(SKUTILS_ERR_BAD_CHAR,
1783 ("Range is missing its upper limit"
1784 " (open-ended ranges are not supported)"));
1785
1786 case SK_NUM_PARSER_NUMBER:
1787 case SK_NUM_PARSER_RANGE:
1788 /* add the entries */
1789 if (range_start < ipwild->m_min[block]) {
1790 ipwild->m_min[block] = range_start;
1791 }
1792 for (i = 0; i < range_length; ++i, ++range_start) {
1793 ipwild->m_blocks[block][_BMAP_INDEX(range_start)]
1794 |= _BMAP_OFFSET(range_start);
1795 }
1796 --range_start;
1797 if (range_start > ipwild->m_max[block]) {
1798 ipwild->m_max[block] = range_start;
1799 }
1800 break;
1801
1802 case SKUTILS_ERR_BAD_CHAR:
1803 default:
1804 return rv;
1805 }
1806 }
1807
1808 sp = numberParserCurrentChar(&parser);
1809 }
1810
1811 if (double_colon != UINT32_MAX) {
1812 if (block == num_blocks) {
1813 /* error */
1814 return parseError(SKUTILS_ERR_BAD_CHAR,
1815 "Cannot have '::' in IP with 8 blocks");
1816 }
1817 memmove(&ipwild->m_min[8 + double_colon - block],
1818 &ipwild->m_min[double_colon],
1819 sizeof(ipwild->m_min[0]) * (block - double_colon));
1820 memmove(&ipwild->m_max[8 + double_colon - block],
1821 &ipwild->m_max[double_colon],
1822 sizeof(ipwild->m_max[0]) * (block - double_colon));
1823 memmove(ipwild->m_blocks[8 + double_colon - block],
1824 ipwild->m_blocks[double_colon],
1825 sizeof(ipwild->m_blocks[0]) * (block - double_colon));
1826 for (i = double_colon; i < (8 + double_colon - block); ++i) {
1827 memset(ipwild->m_blocks[i], 0, sizeof(ipwild->m_blocks[0]));
1828 ipwild->m_blocks[i][_BMAP_INDEX(0)] = _BMAP_OFFSET(0);
1829 ipwild->m_min[i] = 0;
1830 ipwild->m_max[i] = 0;
1831 }
1832 } else if (block != num_blocks) {
1833 /* error */
1834 return parseError(SKUTILS_ERR_SHORT,
1835 ("Only %" PRIu32 "/%" PRIu32 " IP blocks specified"),
1836 block, num_blocks);
1837 }
1838
1839 /* ignore trailing whitespace */
1840 while (isspace((int)*sp)) {
1841 ++sp;
1842 }
1843 if (*sp != '\0') {
1844 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1845 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
1846 }
1847
1848 return SKUTILS_OK;
1849 }
1850
1851
1852 /* parse an IP with an optional CIDR designation */
1853 int
skStringParseCIDR(skipaddr_t * out_val,uint32_t * out_cidr,const char * ip_string)1854 skStringParseCIDR(
1855 skipaddr_t *out_val,
1856 uint32_t *out_cidr,
1857 const char *ip_string)
1858 {
1859 const char *sp;
1860 int rv;
1861
1862 /* try to parse as an ordinary IP address */
1863 rv = skStringParseIP(out_val, ip_string);
1864
1865 /* return if we get an error */
1866 if (rv < 0) {
1867 return rv;
1868 }
1869
1870 /* check if we only got the IP address */
1871 if (rv == 0) {
1872 *out_cidr = (skipaddrIsV6(out_val) ? 128 : 32);
1873 return SKUTILS_OK;
1874 }
1875
1876 /* When rv > 0, we parsed an IP but there is extra text,
1877 * presumably '/' for the CIDR designation. Error if it isn't. */
1878 sp = &ip_string[rv];
1879 if (*sp != '/') {
1880 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1881 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
1882 }
1883
1884 ++sp;
1885 if (*sp == '\0') {
1886 return parseError(SKUTILS_ERR_BAD_CHAR,
1887 "%s '%c'--expected CIDR after slash",
1888 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1889 *sp);
1890 }
1891
1892 /* parse the CIDR value */
1893 rv = skStringParseUint32(out_cidr, sp, 1,
1894 (skipaddrIsV6(out_val) ? 128 : 32));
1895 if (rv > 0) {
1896 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1897 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1898 sp[rv]);
1899 }
1900
1901 return rv;
1902 }
1903
1904
1905 int
skStringParseHostPortPair(sk_sockaddr_array_t ** sockaddr,const char * host_port,uint8_t flags)1906 skStringParseHostPortPair(
1907 sk_sockaddr_array_t **sockaddr,
1908 const char *host_port,
1909 uint8_t flags)
1910 {
1911 sk_sockaddr_array_t *sa;
1912 const char *sp = host_port;
1913 const char *cp;
1914 const char *ep;
1915 const char *colon;
1916 const char *port;
1917 char *host;
1918 uint32_t port_val = 0;
1919 sk_sockaddr_t addr;
1920 int two_colons;
1921 int rv;
1922
1923 if (NULL == sockaddr || NULL == host_port
1924 || ((flags & (PORT_REQUIRED | PORT_PROHIBITED)) ==
1925 (PORT_REQUIRED | PORT_PROHIBITED))
1926 || ((flags & (HOST_REQUIRED | HOST_PROHIBITED)) ==
1927 (HOST_REQUIRED | HOST_PROHIBITED))
1928 || ((flags & (IPV6_REQUIRED | IPV6_PROHIBITED)) ==
1929 (IPV6_REQUIRED | IPV6_PROHIBITED))
1930 || ((flags & (HOST_PROHIBITED | PORT_PROHIBITED)) ==
1931 (HOST_PROHIBITED | PORT_PROHIBITED)))
1932 {
1933 return parseError(SKUTILS_ERR_INVALID,
1934 "Programmer error: Invalid flag combination");
1935 }
1936
1937 #if !SK_ENABLE_INET6_NETWORKING
1938 if (flags & IPV6_REQUIRED) {
1939 return parseError(SKUTILS_ERR_INVALID,
1940 ("IPv6 address required yet"
1941 " IPv6 addresses not supported"));
1942 }
1943 #endif /* !SK_ENABLE_INET6_NETWORKING */
1944
1945 /* ignore leading whitespace */
1946 while (*sp && isspace((int)*sp)) {
1947 ++sp;
1948 }
1949 if ('\0' == *sp) {
1950 /* whitespace only or empty string */
1951 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
1952 }
1953
1954 /* move 'ep' forward to next whitespace char or to end of string */
1955 ep = sp + 1;
1956 while (*ep && !isspace((int)*ep)) {
1957 ++ep;
1958 }
1959 if ('\0' != *ep) {
1960 /* found whitespace; ensure it is only trailing whitespace and
1961 * not embedded whitespace */
1962 cp = ep;
1963 while (*cp && isspace((int)*cp)) {
1964 ++cp;
1965 }
1966 if ('\0' != *cp) {
1967 return parseError(SKUTILS_ERR_BAD_CHAR,
1968 "%s--embedded whitespace found in input",
1969 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1970 }
1971 }
1972
1973 /* get possible host:port separator ':', which could be part of an
1974 * IPv6 address if there is no port */
1975 colon = strrchr(sp, ':');
1976 two_colons = (colon && colon != strchr(sp, ':'));
1977
1978 /* set 'ep' to end of the host portion of input */
1979 if ('[' == *sp) {
1980 cp = strrchr(sp, ']');
1981 if (cp == NULL) {
1982 return parseError(SKUTILS_ERR_BAD_CHAR,
1983 "Cannot find closing ']' character");
1984 }
1985 /* character after ']' must be end of string or the ':' that
1986 * separates the host from the port */
1987 if ((cp + 1 != ep) && (cp + 1 != colon)) {
1988 return parseError(SKUTILS_ERR_BAD_CHAR,
1989 "%s--unexpected character after ']': %c",
1990 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1991 *(cp+1));
1992 }
1993 if (colon && (colon < cp)) {
1994 /* if final ':' occurs before ']', assume function was
1995 * passed an IPv6 address with no port */
1996 colon = NULL;
1997 }
1998 ++sp;
1999 ep = cp;
2000
2001 } else if (two_colons) {
2002 /* assume we have an IPv6 address not contained in [...] */
2003 colon = NULL;
2004
2005 } else if (colon) {
2006 ep = colon;
2007 }
2008
2009 /* Check to see if the presumed host is actually a port */
2010 if (colon == NULL && (sp + strspn(sp, "0123456789") == ep)) {
2011 if (flags & HOST_REQUIRED) {
2012 return parseError(SKUTILS_ERR_OTHER,
2013 "Expected a host name or IP address");
2014 }
2015 colon = sp - 1; /* -1 due to increment below */
2016 ep = sp;
2017 }
2018
2019 /* Parse the port */
2020 if (colon) {
2021 port = colon + 1;
2022 if (flags & PORT_PROHIBITED) {
2023 return parseError(SKUTILS_ERR_OTHER,
2024 "Expected a host name or IP only");
2025 }
2026
2027 rv = skStringParseUint32(&port_val, port, 0, UINT16_MAX);
2028 if (rv < 0) {
2029 /* bad parse */
2030 if (SKUTILS_ERR_EMPTY == rv) {
2031 return parseError(SKUTILS_ERR_SHORT, "Missing port value");
2032 }
2033 return parseError((silk_utils_errcode_t)rv,
2034 "Error parsing port: %s",
2035 PARSE_ERRORCODE_MSG(rv));
2036 }
2037 if (rv > 0) {
2038 /* text after port */
2039 return parseError(SKUTILS_ERR_BAD_CHAR,
2040 "Error parsing port: Unexpected text after port");
2041 }
2042 } else if (flags & PORT_REQUIRED) {
2043 return parseError(SKUTILS_ERR_OTHER,
2044 "Cannot find port and port is required");
2045 } else {
2046 port = NULL;
2047 }
2048
2049 if (ep == sp) {
2050 /* no host */
2051 host = NULL;
2052 } else if (flags & HOST_PROHIBITED) {
2053 return parseError(SKUTILS_ERR_OTHER,
2054 "Found a host name when host was prohibited");
2055 } else {
2056 /* copy the hostname or IP so we can lop off the port */
2057 host = (char*)malloc((ep - sp + 1u) * sizeof(char));
2058 if (NULL == host) {
2059 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2060 }
2061 memcpy(host, sp, (ep - sp + 1u) * sizeof(char));
2062 host[ep - sp] = '\0';
2063 }
2064
2065 /* fill an sk_vector_t with sk_sockaddr_t structures that are
2066 * obtained by using either getaddrinfo() to parse the host:port
2067 * pair or gethostbyname() to parse the host */
2068 {
2069 sk_vector_t *vec;
2070 #if USE_GETADDRINFO
2071 const char *resolv_constraint = "";
2072 struct addrinfo *addrinfo;
2073 struct addrinfo *current;
2074 struct addrinfo hints;
2075 char port_buf[7];
2076 char *port_str;
2077
2078 memset(&hints, 0, sizeof(hints));
2079 if (!SK_ENABLE_INET6_NETWORKING || (flags & IPV6_PROHIBITED)) {
2080 resolv_constraint = " as an IPv4 address";
2081 hints.ai_family = AF_INET;
2082 } else if (flags & IPV6_REQUIRED) {
2083 resolv_constraint = " as an IPv6 address";
2084 hints.ai_family = AF_INET6;
2085 } else {
2086 hints.ai_family = AF_UNSPEC;
2087 }
2088 if (host == NULL) {
2089 hints.ai_flags = AI_PASSIVE;
2090 }
2091 /* hints.ai_flags |= AI_ADDRCONFIG; */
2092 if (port == NULL) {
2093 port_str = NULL;
2094 } else {
2095 snprintf(port_buf, sizeof(port_buf), "%" PRIu32, port_val);
2096 port_str = port_buf;
2097 }
2098
2099 /* The following is a lie, but a white one. We need a
2100 * non-zero socktype in order for Solaris to agree with
2101 * numeric ports that aren't in the /etc/services file. */
2102 hints.ai_socktype = SOCK_STREAM;
2103
2104 rv = getaddrinfo(host, port_str, &hints, &addrinfo);
2105 if (rv != 0) {
2106 if (host) {
2107 rv = parseError(SKUTILS_ERR_RESOLVE,
2108 "Unable to resolve '%s'%s: %s",
2109 host, resolv_constraint, gai_strerror(rv));
2110 free(host);
2111 } else {
2112 rv = parseError(SKUTILS_ERR_RESOLVE,
2113 "Could not register passive port %s: %s",
2114 port_str, gai_strerror(rv));
2115 }
2116 return rv;
2117 }
2118
2119 vec = skVectorNew(sizeof(addr));
2120 if (vec == NULL) {
2121 freeaddrinfo(addrinfo);
2122 if (host) {
2123 free(host);
2124 }
2125 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2126 }
2127
2128 current = addrinfo;
2129 while (current) {
2130 switch (current->ai_addr->sa_family) {
2131 #if SK_ENABLE_INET6_NETWORKING
2132 case AF_INET6:
2133 addr.v6 = *(struct sockaddr_in6 *)(current->ai_addr);
2134 break;
2135 #endif /* SK_ENABLE_INET6_NETWORKING */
2136 case AF_INET:
2137 addr.v4 = *(struct sockaddr_in *)(current->ai_addr);
2138 break;
2139 default:
2140 current = current->ai_next;
2141 continue;
2142 }
2143 rv = skVectorAppendValue(vec, &addr);
2144 if (rv != 0) {
2145 skVectorDestroy(vec);
2146 if (host) {
2147 free(host);
2148 }
2149 freeaddrinfo(addrinfo);
2150 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2151 }
2152 current = current->ai_next;
2153 }
2154 freeaddrinfo(addrinfo);
2155
2156 #else /* #if !USE_GETADDRINFO */
2157 vec = skVectorNew(sizeof(addr));
2158 if (vec == NULL) {
2159 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2160 }
2161 memset(&addr, 0, sizeof(addr));
2162 addr.v4.sin_family = AF_INET;
2163 addr.v4.sin_port = htons((uint16_t)port_val);
2164 if (!host) {
2165 addr.v4.sin_addr.s_addr = htonl(INADDR_ANY);
2166 rv = skVectorAppendValue(vec, &addr);
2167 if (rv != 0) {
2168 skVectorDestroy(vec);
2169 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2170 }
2171 } else {
2172 struct hostent *he;
2173 char **current;
2174
2175 he = gethostbyname(host);
2176 if (he == NULL || (he->h_addrtype != AF_INET)) {
2177 rv = parseError(SKUTILS_ERR_RESOLVE,
2178 "Unable to resolve '%s' as an IPv4 address",
2179 host);
2180 free(host);
2181 skVectorDestroy(vec);
2182 return rv;
2183 }
2184
2185 current = he->h_addr_list;
2186 while (*current) {
2187 memcpy(&addr.v4.sin_addr, *current, he->h_length);
2188 rv = skVectorAppendValue(vec, &addr);
2189 if (rv != 0) {
2190 free(host);
2191 skVectorDestroy(vec);
2192 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2193 }
2194 current++;
2195 }
2196 }
2197 #endif /* USE_GETADDRINFO */
2198
2199 sa = (sk_sockaddr_array_t*)calloc(1, sizeof(sk_sockaddr_array_t));
2200 if (sa == NULL) {
2201 free(host);
2202 skVectorDestroy(vec);
2203 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2204 }
2205 sa->name = host;
2206
2207 sa->num_addrs = skVectorGetCount(vec);
2208 sa->addrs = (sk_sockaddr_t*)skVectorToArrayAlloc(vec);
2209 skVectorDestroy(vec);
2210 if (sa->addrs == NULL) {
2211 skSockaddrArrayDestroy(sa);
2212 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2213 }
2214
2215 if (host || (flags & HOST_PROHIBITED)) {
2216 /* grab the value that was provided */
2217 sa->host_port_pair = strdup(host_port);
2218 if (!sa->host_port_pair) {
2219 skSockaddrArrayDestroy(sa);
2220 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2221 }
2222 } else {
2223 const size_t buf_size = 12;
2224 sa->host_port_pair = (char *)malloc(buf_size * sizeof(char));
2225 if (!sa->host_port_pair) {
2226 skSockaddrArrayDestroy(sa);
2227 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2228 }
2229 if (flags & IPV6_PROHIBITED) {
2230 rv = snprintf(sa->host_port_pair,buf_size, "*:%u", port_val);
2231 } else {
2232 rv = snprintf(sa->host_port_pair,buf_size, "[*]:%u", port_val);
2233 }
2234 if ((size_t)rv > buf_size) {
2235 skAbort();
2236 }
2237 }
2238
2239 *sockaddr = sa;
2240 }
2241
2242 return SKUTILS_OK;
2243 }
2244
2245
2246 /*
2247 * Helper function for skStringParseDatetime() to handle parsing of
2248 * the fractional seconds.
2249 *
2250 * Fractional seconds begin in 'start_char'. 'end_char' is set to
2251 * the character following the fractional seconds, and 'end_char'
2252 * must be provided. The fractional seconds are stored in the
2253 * value referenced by 'msec'. Return SKUTILS_OK or a negative
2254 * skutils-parse-error value.
2255 */
2256 static int
parseDatetimeFractionalSeconds(const char * start_char,char ** end_char,long * msec)2257 parseDatetimeFractionalSeconds(
2258 const char *start_char,
2259 char **end_char,
2260 long *msec)
2261 {
2262 long val;
2263 size_t num_digits;
2264
2265 if (!isdigit((int)*start_char)) {
2266 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2267 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2268 *start_char);
2269 }
2270 /* parse the value */
2271 errno = 0;
2272 val = strtol(start_char, end_char, 10);
2273 num_digits = (*end_char - start_char);
2274 if (0 == num_digits) {
2275 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2276 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2277 *start_char);
2278 }
2279 if (val == LONG_MAX && errno == ERANGE) {
2280 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2281 }
2282 if (val < 0) {
2283 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2284 }
2285 /* multiply or divide as needed given the number of digits parsed */
2286 switch (num_digits) {
2287 case 0: skAbortBadCase(num_digits);
2288 case 1: *msec = val * 100; break;
2289 case 2: *msec = val * 10; break;
2290 case 3: *msec = val; break;
2291 case 4: *msec = val / 10; break;
2292 case 5: *msec = val / 100; break;
2293 case 6: *msec = val / 1000; break;
2294 case 7: *msec = val / 10000; break;
2295 case 8: *msec = val / 100000; break;
2296 case 9: *msec = val / 1000000; break;
2297 case 10: *msec = val / 10000000; break;
2298 case 11: *msec = val / 100000000; break;
2299 case 12:
2300 default:
2301 val /= 1000000000;
2302 for ( ; num_digits > 12; --num_digits) {
2303 val /= 10;
2304 }
2305 *msec = val;
2306 break;
2307 }
2308 return SKUTILS_OK;
2309 }
2310
2311
2312 /* time string to struct sktime_st; see utils.h for details */
2313 int
skStringParseDatetime(sktime_t * date_val,const char * date_string,unsigned int * out_flags)2314 skStringParseDatetime(
2315 sktime_t *date_val,
2316 const char *date_string,
2317 unsigned int *out_flags)
2318 {
2319 const unsigned int min_precision = SK_PARSED_DATETIME_DAY;
2320 struct tm ts;
2321 time_t t;
2322 const char *sp;
2323 char *ep;
2324 const char delim[] = {'\0', '/', '/', ':', ':', ':', '.'};
2325 long val;
2326 long msec = 0;
2327 unsigned int i;
2328 int rv;
2329
2330 /* check inputs */
2331 assert(date_val);
2332 if (NULL == date_string) {
2333 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2334 }
2335
2336 /* initialize */
2337 sp = date_string;
2338 memset(&ts, 0, sizeof(struct tm));
2339
2340 /* use "unknown" value for Daylight Saving Time flag */
2341 ts.tm_isdst = -1;
2342
2343 /* ignore leading whitespace */
2344 while (*sp && isspace((int)*sp)) {
2345 ++sp;
2346 }
2347 if ('\0' == *sp) {
2348 /* whitespace only or empty string */
2349 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
2350 }
2351
2352 /* if the date contains only digits and a decimal point(s) and is
2353 * at least 9 digits long, treat it as an epoch time */
2354 if (strspn(sp, ".0123456789") > 8) {
2355 long epoch;
2356
2357 /* parse the seconds */
2358 errno = 0;
2359 val = strtol(sp, &ep, 10);
2360 if (sp == ep) {
2361 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2362 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
2363 }
2364 if (val == LONG_MAX && errno == ERANGE) {
2365 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2366 }
2367 if (val < 0) {
2368 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2369 }
2370
2371 /* make sure value is in range */
2372 if ((val < STRING_PARSE_MIN_EPOCH)
2373 || ((unsigned long)val > STRING_PARSE_MAX_EPOCH))
2374 {
2375 return parseError(((val < STRING_PARSE_MIN_EPOCH)
2376 ? SKUTILS_ERR_MINIMUM
2377 : SKUTILS_ERR_MAXIMUM),
2378 ("Epoch value (%ld) out of range:"
2379 " use %d <= epoch <= %u"),
2380 val,
2381 STRING_PARSE_MIN_EPOCH, STRING_PARSE_MAX_EPOCH);
2382 }
2383
2384 epoch = val;
2385 if ('.' == *ep && isdigit((int)*(ep+1))) {
2386 /* parse fractional seconds */
2387 sp = ep + 1;
2388 rv = parseDatetimeFractionalSeconds(sp, &ep, &msec);
2389 if (rv) {
2390 return rv;
2391 }
2392 }
2393
2394 /* handle the end of the string, to see if we are attempting
2395 * to parse something as epoch that we shouldn't */
2396 if (*ep != '\0' && !isspace((int)*ep)) {
2397 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2398 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *ep);
2399 }
2400
2401 /* ignore trailing whitespace */
2402 sp = ep;
2403 while (*sp && isspace((int)*sp)) {
2404 ++sp;
2405 }
2406 if ('\0' != *sp) {
2407 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2408 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
2409 }
2410 if (out_flags) {
2411 if (strchr(date_string, '.')) {
2412 *out_flags = SK_PARSED_DATETIME_FRACSEC;
2413 } else if (0 == epoch % 3600) {
2414 /* at least hour precision */
2415 if (0 == epoch % 86400) {
2416 *out_flags = SK_PARSED_DATETIME_DAY;
2417 } else {
2418 *out_flags = SK_PARSED_DATETIME_HOUR;
2419 }
2420 } else if (0 == epoch % 60) {
2421 *out_flags = SK_PARSED_DATETIME_MINUTE;
2422 } else {
2423 *out_flags = SK_PARSED_DATETIME_SECOND;
2424 }
2425 *out_flags |= SK_PARSED_DATETIME_EPOCH;
2426 }
2427 *date_val = sktimeCreate(epoch, msec);
2428 return SKUTILS_OK;
2429 }
2430
2431 /* 'i' is the part of the date we have successfully parsed;
2432 * 1=year, 2=month, 3=day, 4=hour, 5=min, 6=sec, 7=msec */
2433 i = 0;
2434 while (*sp && (i < (sizeof(delim)/sizeof(char)))) {
2435 /* this will catch things like double ':' in the string */
2436 if ( !isdigit((int)*sp)) {
2437 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2438 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
2439 }
2440
2441 if (6 == i) {
2442 rv = parseDatetimeFractionalSeconds(sp, &ep, &msec);
2443 if (rv) {
2444 return rv;
2445 }
2446 } else {
2447 /* parse the digit */
2448 errno = 0;
2449 val = strtol(sp, &ep, 10);
2450
2451 if (sp == ep) {
2452 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2453 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2454 *sp);
2455 }
2456 if (val == LONG_MAX && errno == ERANGE) {
2457 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2458 }
2459 if (val < 0) {
2460 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2461 }
2462 }
2463
2464 /* check that value is valid given what we are parsing */
2465 switch (i) {
2466 case 0: /* year */
2467 if (val < STRING_PARSE_MIN_YEAR || val > STRING_PARSE_MAX_YEAR) {
2468 return parseError(((val < STRING_PARSE_MIN_YEAR)
2469 ? SKUTILS_ERR_MINIMUM
2470 : SKUTILS_ERR_MAXIMUM),
2471 ("Year value (%ld) out of range:"
2472 " use %d <= year <= %d"),
2473 val, STRING_PARSE_MIN_YEAR,
2474 STRING_PARSE_MAX_YEAR);
2475 }
2476 ts.tm_year = val - 1900;
2477 break;
2478 case 1: /* month */
2479 if (val < 1 || val > 12) {
2480 return parseError(((val < 1)
2481 ? SKUTILS_ERR_MINIMUM
2482 : SKUTILS_ERR_MAXIMUM),
2483 ("Month value (%ld) out of range:"
2484 " use %d <= month <= %d"),
2485 val, 1, 12);
2486 }
2487 ts.tm_mon = val - 1;
2488 break;
2489 case 2: /* day */
2490 if (val < 1
2491 || val > skGetMaxDayInMonth((1900 + ts.tm_year),
2492 (1 + ts.tm_mon)))
2493 {
2494 return parseError(((val < 1)
2495 ? SKUTILS_ERR_MINIMUM
2496 : SKUTILS_ERR_MAXIMUM),
2497 ("Day value (%ld) out of range:"
2498 " use %d <= day <= %d"),
2499 val, 1,
2500 skGetMaxDayInMonth((1900 + ts.tm_year),
2501 (1 + ts.tm_mon)));
2502 }
2503 ts.tm_mday = val;
2504 break;
2505 case 3: /* hour */
2506 if (val > 23) {
2507 return parseError(SKUTILS_ERR_MAXIMUM,
2508 ("Hour value (%ld) out of range:"
2509 " use %d <= hour <= %d"),
2510 val, 0, 23);
2511 }
2512 ts.tm_hour = val;
2513 break;
2514 case 4: /* minute */
2515 if (val > 59) {
2516 return parseError(SKUTILS_ERR_MAXIMUM,
2517 ("Minute value (%ld) out of range:"
2518 " use %d <= minute <= %d"),
2519 val, 0, 59);
2520 }
2521 ts.tm_min = val;
2522 break;
2523 case 5: /* second */
2524 if (val > 59) {
2525 return parseError(SKUTILS_ERR_MAXIMUM,
2526 ("Second value (%ld) out of range:"
2527 " use %d <= second <= %d"),
2528 val, 0, 59);
2529 }
2530 ts.tm_sec = val;
2531 break;
2532 case 6: /* fractional seconds; handled above */
2533 break;
2534 default:
2535 /* should never get here */
2536 skAbortBadCase(i);
2537 }
2538
2539 /* we parsed the number; move to the delimiter */
2540 ++i;
2541 sp = ep;
2542
2543 /* check for whitespace or end of string */
2544 if (('\0' == *sp) || isspace((int)*sp)) {
2545 break;
2546 }
2547
2548 /* check that delimiter is what we expect; if so move over it
2549 * to next character */
2550 if (delim[i]) {
2551 if (*sp == delim[i]) {
2552 ++sp;
2553 } else if (i == 3 && (*sp == 'T')) {
2554 /* allow a ':' or a 'T' to separate the day and hour */
2555 ++sp;
2556 } else {
2557 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2558 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2559 *sp);
2560 }
2561 }
2562 }
2563
2564 /* space is allowed at end of string; eat it */
2565 ep = (char*)sp;
2566 while (*sp && isspace((int)*sp)) {
2567 ++sp;
2568 }
2569
2570 /* check for junk at end of string; if so, report error at 'ep' */
2571 if ('\0' != *sp) {
2572 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2573 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *ep);
2574 }
2575
2576 /* if the caller wants to know the last state parsed, we update
2577 * their variable. */
2578 if (out_flags != NULL) {
2579 *out_flags = i;
2580 }
2581
2582 /* need at least year/month/day */
2583 if (i < min_precision) {
2584 return parseError(SKUTILS_ERR_SHORT,
2585 "Date '%s' does not have at least day precision",
2586 date_string);
2587 }
2588
2589 /* convert the time */
2590 #if SK_ENABLE_LOCALTIME
2591 t = mktime(&ts);
2592 #else
2593 t = timegm(&ts);
2594 #endif
2595 if (t == (time_t)-1) {
2596 return -1;
2597 }
2598
2599 *date_val = sktimeCreate(t, msec);
2600 return SKUTILS_OK;
2601 }
2602
2603
2604 /* parses string of the form DATETIME[-DATETIME], where DATETIME is
2605 * parsed by skStringParseDatetime(). see header for details. */
2606 int
skStringParseDatetimeRange(sktime_t * start,sktime_t * end,const char * s_datetime,unsigned int * start_precision,unsigned int * end_precision)2607 skStringParseDatetimeRange(
2608 sktime_t *start,
2609 sktime_t *end,
2610 const char *s_datetime,
2611 unsigned int *start_precision,
2612 unsigned int *end_precision)
2613 {
2614 char *s_start_time;
2615 char *s_end_time;
2616 int rv = 0;
2617
2618 /* check inputs */
2619 assert(start);
2620 assert(end);
2621 if (s_datetime == NULL) {
2622 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2623 }
2624
2625 /* copy the string, since we are going to modify it */
2626 s_start_time = strdup(s_datetime);
2627 if (!s_start_time) {
2628 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2629 }
2630
2631 /* search for dash. if dash does not exist, parse entire string
2632 * as start date. if dash does exist, parse string on left as
2633 * start date and string on right as end date.
2634 */
2635 s_end_time = strchr(s_start_time, '-');
2636 if (s_end_time != NULL) {
2637 /* change the dash to a NUL to create two separate strings */
2638 *s_end_time = '\0';
2639 /* set the s_end_time pointer to be the char after the dash */
2640 ++s_end_time;
2641 /* treat missing end-time as infinity */
2642 if (*s_end_time == '\0') {
2643 s_end_time = NULL;
2644 }
2645 }
2646
2647 /* parse start */
2648 rv = skStringParseDatetime(start, s_start_time, start_precision);
2649 if (s_end_time == NULL) {
2650 *end = INT64_MAX;
2651 } else if (rv == 0) {
2652 rv = skStringParseDatetime(end, s_end_time, end_precision);
2653 }
2654
2655 free(s_start_time);
2656
2657 /* check error conditions and return error if necessary */
2658 if (rv) {
2659 return rv;
2660 }
2661
2662 if (*end < *start) {
2663 return parseError(SKUTILS_ERR_BAD_RANGE, PE_NULL);
2664 }
2665
2666 return SKUTILS_OK;
2667 }
2668
2669
2670 /* set 'ceiling_time' to the greatest value that does not change the
2671 * 'precision' of 't'. see header for details. */
2672 int
skDatetimeCeiling(sktime_t * ceiling_time,const sktime_t * t,unsigned int precision)2673 skDatetimeCeiling(
2674 sktime_t *ceiling_time,
2675 const sktime_t *t,
2676 unsigned int precision)
2677 {
2678 struct tm ts;
2679 struct tm *rv;
2680 time_t t_sec;
2681
2682 assert(t);
2683 assert(ceiling_time);
2684
2685 if ((precision
2686 & ~(SK_PARSED_DATETIME_MASK_PRECISION | SK_PARSED_DATETIME_EPOCH))
2687 || (0 == precision))
2688 {
2689 return -1;
2690 }
2691 precision &= SK_PARSED_DATETIME_MASK_PRECISION;
2692
2693 t_sec = (time_t)sktimeGetSeconds(*t);
2694
2695 #if SK_ENABLE_LOCALTIME
2696 rv = localtime_r(&t_sec, &ts);
2697 #else
2698 rv = gmtime_r(&t_sec, &ts);
2699 #endif
2700 if (NULL == rv) {
2701 return -1;
2702 }
2703
2704 /* 'precision' is what we know; we need to set everything that is
2705 * "finer" than that value. */
2706 switch (precision) {
2707 case SK_PARSED_DATETIME_YEAR: /* know year, set month */
2708 ts.tm_mon = 11;
2709 /* FALLTHROUGH */
2710
2711 case SK_PARSED_DATETIME_MONTH: /* know month, set month-day */
2712 ts.tm_mday = skGetMaxDayInMonth((1900 + ts.tm_year), (1 + ts.tm_mon));
2713 /* FALLTHROUGH */
2714
2715 case SK_PARSED_DATETIME_DAY: /* know month-day, set hour */
2716 ts.tm_hour = 23;
2717 /* FALLTHROUGH */
2718
2719 case SK_PARSED_DATETIME_HOUR: /* know hour, set min */
2720 ts.tm_min = 59;
2721 /* FALLTHROUGH */
2722
2723 case SK_PARSED_DATETIME_MINUTE: /* know min, set sec */
2724 ts.tm_sec = 59;
2725 break;
2726
2727 case SK_PARSED_DATETIME_SECOND:
2728 /* know sec, just set fractional-seconds */
2729 *ceiling_time = sktimeCreate(t_sec, 999);
2730 return 0;
2731
2732 case SK_PARSED_DATETIME_FRACSEC:
2733 /* already at max precision, just return what we were given */
2734 *ceiling_time = *t;
2735 return 0;
2736
2737 default:
2738 skAbortBadCase(precision);
2739 }
2740
2741 /* we have reports of the following causing problems on some
2742 * versions of Solaris, but we cannot re-create... */
2743 ts.tm_isdst = -1;
2744
2745 /* convert the time */
2746 #if SK_ENABLE_LOCALTIME
2747 t_sec = mktime(&ts);
2748 #else
2749 t_sec = timegm(&ts);
2750 #endif
2751 if (t_sec == (time_t)-1) {
2752 return -1;
2753 }
2754
2755 /* convert seconds to milliseconds */
2756 *ceiling_time = sktimeCreate(t_sec, 999);
2757
2758 return 0;
2759 }
2760
2761
2762 /* set 'floor_time' to the lowest value that does not change the
2763 * 'precision' of 't'. see header for details. */
2764 int
skDatetimeFloor(sktime_t * floor_time,const sktime_t * t,unsigned int precision)2765 skDatetimeFloor(
2766 sktime_t *floor_time,
2767 const sktime_t *t,
2768 unsigned int precision)
2769 {
2770 struct tm ts;
2771 struct tm *rv;
2772 time_t t_sec;
2773
2774 assert(t);
2775 assert(floor_time);
2776
2777 if ((precision
2778 & ~(SK_PARSED_DATETIME_MASK_PRECISION | SK_PARSED_DATETIME_EPOCH))
2779 || (0 == precision))
2780 {
2781 return -1;
2782 }
2783 precision &= SK_PARSED_DATETIME_MASK_PRECISION;
2784
2785 t_sec = (time_t)sktimeGetSeconds(*t);
2786
2787 #if SK_ENABLE_LOCALTIME
2788 rv = localtime_r(&t_sec, &ts);
2789 #else
2790 rv = gmtime_r(&t_sec, &ts);
2791 #endif
2792 if (NULL == rv) {
2793 return -1;
2794 }
2795
2796 /* 'precision' is what we know; we need to clear everything that is
2797 * "finer" than that value. */
2798 switch (precision) {
2799 case SK_PARSED_DATETIME_YEAR: /* know year, set month */
2800 ts.tm_mon = 0;
2801 /* FALLTHROUGH */
2802
2803 case SK_PARSED_DATETIME_MONTH: /* know month, set month-day */
2804 ts.tm_mday = 1;
2805 /* FALLTHROUGH */
2806
2807 case SK_PARSED_DATETIME_DAY: /* know month-day, set hour */
2808 ts.tm_hour = 0;
2809 /* FALLTHROUGH */
2810
2811 case SK_PARSED_DATETIME_HOUR: /* know hour, set min */
2812 ts.tm_min = 0;
2813 /* FALLTHROUGH */
2814
2815 case SK_PARSED_DATETIME_MINUTE: /* know min, set sec */
2816 ts.tm_sec = 0;
2817 break;
2818
2819 case SK_PARSED_DATETIME_SECOND:
2820 /* know sec, just set fractional-seconds */
2821 *floor_time = sktimeCreate(t_sec, 0);
2822 return 0;
2823
2824 case SK_PARSED_DATETIME_FRACSEC:
2825 /* already at max precision, just return what we were given */
2826 *floor_time = *t;
2827 return 0;
2828
2829 default:
2830 skAbortBadCase(precision);
2831 }
2832
2833 /* we have reports of the following causing problems on some
2834 * versions of Solaris, but we cannot re-create... */
2835 ts.tm_isdst = -1;
2836
2837 /* convert the time */
2838 #if SK_ENABLE_LOCALTIME
2839 t_sec = mktime(&ts);
2840 #else
2841 t_sec = timegm(&ts);
2842 #endif
2843 if (t_sec == (time_t)-1) {
2844 return -1;
2845 }
2846
2847 /* convert seconds to milliseconds */
2848 *floor_time = sktimeCreate(t_sec, 0);
2849
2850 return 0;
2851 }
2852
2853
2854 /* parse string as TCP flags. see header for details. */
2855 int
skStringParseTCPFlags(uint8_t * result,const char * flag_string)2856 skStringParseTCPFlags(
2857 uint8_t *result,
2858 const char *flag_string)
2859 {
2860 const char *cp = flag_string;
2861
2862 /* check inputs */
2863 assert(result);
2864 if (flag_string == NULL) {
2865 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2866 }
2867
2868 /* parse each character, unless it is a terminating NULL or an
2869 * illegal character.
2870 */
2871 *result = 0;
2872 while (*cp) {
2873 switch (*cp) {
2874 case 'f':
2875 case 'F':
2876 TCP_FLAG_SET_FLAG(*result, FIN_FLAG);
2877 break;
2878 case 's':
2879 case 'S':
2880 TCP_FLAG_SET_FLAG(*result, SYN_FLAG);
2881 break;
2882 case 'r':
2883 case 'R':
2884 TCP_FLAG_SET_FLAG(*result, RST_FLAG);
2885 break;
2886 case 'p':
2887 case 'P':
2888 TCP_FLAG_SET_FLAG(*result, PSH_FLAG);
2889 break;
2890 case 'a':
2891 case 'A':
2892 TCP_FLAG_SET_FLAG(*result, ACK_FLAG);
2893 break;
2894 case 'u':
2895 case 'U':
2896 TCP_FLAG_SET_FLAG(*result, URG_FLAG);
2897 break;
2898 case 'e':
2899 case 'E':
2900 TCP_FLAG_SET_FLAG(*result, ECE_FLAG);
2901 break;
2902 case 'c':
2903 case 'C':
2904 TCP_FLAG_SET_FLAG(*result, CWR_FLAG);
2905 break;
2906 case ' ':
2907 break;
2908 default:
2909 if (!isspace((int)*cp)) {
2910 /* reached illegal, non-space character */
2911 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2912 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2913 *cp);
2914 }
2915 break;
2916 }
2917 ++cp;
2918 }
2919
2920 return SKUTILS_OK;
2921 }
2922
2923
2924 /* parse flag definition in the form high/mask. see header for
2925 * details. */
2926 int
skStringParseTCPFlagsHighMask(uint8_t * high,uint8_t * mask,const char * flag_string)2927 skStringParseTCPFlagsHighMask(
2928 uint8_t *high,
2929 uint8_t *mask,
2930 const char *flag_string)
2931 {
2932 const char *cp = flag_string;
2933 uint8_t *result;
2934
2935 /* check inputs */
2936 assert(high);
2937 assert(mask);
2938 if (flag_string == NULL) {
2939 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2940 }
2941
2942 *high = 0;
2943 *mask = 0;
2944 result = high;
2945
2946 /* parse each character, unless it is a terminating NULL or an
2947 * illegal character.
2948 */
2949 while (*cp) {
2950 switch (*cp) {
2951 case 'f':
2952 case 'F':
2953 TCP_FLAG_SET_FLAG(*result, FIN_FLAG);
2954 break;
2955 case 's':
2956 case 'S':
2957 TCP_FLAG_SET_FLAG(*result, SYN_FLAG);
2958 break;
2959 case 'r':
2960 case 'R':
2961 TCP_FLAG_SET_FLAG(*result, RST_FLAG);
2962 break;
2963 case 'p':
2964 case 'P':
2965 TCP_FLAG_SET_FLAG(*result, PSH_FLAG);
2966 break;
2967 case 'a':
2968 case 'A':
2969 TCP_FLAG_SET_FLAG(*result, ACK_FLAG);
2970 break;
2971 case 'u':
2972 case 'U':
2973 TCP_FLAG_SET_FLAG(*result, URG_FLAG);
2974 break;
2975 case 'e':
2976 case 'E':
2977 TCP_FLAG_SET_FLAG(*result, ECE_FLAG);
2978 break;
2979 case 'c':
2980 case 'C':
2981 TCP_FLAG_SET_FLAG(*result, CWR_FLAG);
2982 break;
2983 case '/':
2984 if (result == mask) {
2985 /* double slash */
2986 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2987 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2988 *cp);
2989 }
2990 result = mask;
2991 break;
2992 case ' ':
2993 break;
2994 default:
2995 if (!isspace((int)*cp)) {
2996 /* reached illegal, non-space character */
2997 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2998 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2999 *cp);
3000 }
3001 break;
3002 }
3003 ++cp;
3004 }
3005
3006 /* check if we reached end of string before '/' character was found */
3007 if (result == high) {
3008 if (*high == 0) {
3009 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3010 }
3011 return parseError(SKUTILS_ERR_SHORT, "Missing '/' character");
3012 }
3013
3014 if (*mask == 0) {
3015 return parseError(SKUTILS_ERR_SHORT, "Missing masks flags value");
3016 }
3017
3018 /* make sure high is a proper subset of mask */
3019 if ((*high & *mask) != *high) {
3020 return parseError(SKUTILS_ERR_BAD_RANGE,
3021 "High flags is not subset of mask flags");
3022 }
3023
3024 /* success */
3025 return SKUTILS_OK;
3026 }
3027
3028
3029 /* parse string as TCP state flags. see header for details. */
3030 int
skStringParseTCPState(uint8_t * result,const char * flag_string)3031 skStringParseTCPState(
3032 uint8_t *result,
3033 const char *flag_string)
3034 {
3035 const char *cp = flag_string;
3036
3037 /* check inputs */
3038 assert(result);
3039 if (flag_string == NULL) {
3040 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3041 }
3042
3043 /* parse each character, unless it is a terminating NULL or an
3044 * illegal character.
3045 */
3046 *result = 0;
3047 while (*cp) {
3048 switch (*cp) {
3049 case 't':
3050 case 'T':
3051 *result |= SK_TCPSTATE_TIMEOUT_KILLED;
3052 break;
3053 case 'c':
3054 case 'C':
3055 *result |= SK_TCPSTATE_TIMEOUT_STARTED;
3056 break;
3057 case 'f':
3058 case 'F':
3059 *result |= SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
3060 break;
3061 case 's':
3062 case 'S':
3063 *result |= SK_TCPSTATE_UNIFORM_PACKET_SIZE;
3064 break;
3065 case ' ':
3066 break;
3067 default:
3068 if (!isspace((int)*cp)) {
3069 /* reached illegal, non-space character */
3070 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3071 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3072 *cp);
3073 }
3074 break;
3075 }
3076 ++cp;
3077 }
3078
3079 return SKUTILS_OK;
3080 }
3081
3082
3083 /* parse TCP state flag definition in the form high/mask. see header
3084 * for details. */
3085 int
skStringParseTCPStateHighMask(uint8_t * high,uint8_t * mask,const char * flag_string)3086 skStringParseTCPStateHighMask(
3087 uint8_t *high,
3088 uint8_t *mask,
3089 const char *flag_string)
3090 {
3091 const char *cp = flag_string;
3092 uint8_t *result;
3093
3094 /* check inputs */
3095 assert(high);
3096 assert(mask);
3097 if (flag_string == NULL) {
3098 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3099 }
3100
3101 *high = 0;
3102 *mask = 0;
3103 result = high;
3104
3105 /* parse each character, unless it is a terminating NULL or an
3106 * illegal character.
3107 */
3108 while (*cp) {
3109 switch (*cp) {
3110 case 't':
3111 case 'T':
3112 *result |= SK_TCPSTATE_TIMEOUT_KILLED;
3113 break;
3114 case 'c':
3115 case 'C':
3116 *result |= SK_TCPSTATE_TIMEOUT_STARTED;
3117 break;
3118 case 'f':
3119 case 'F':
3120 *result |= SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
3121 break;
3122 case 's':
3123 case 'S':
3124 *result |= SK_TCPSTATE_UNIFORM_PACKET_SIZE;
3125 break;
3126 case '/':
3127 if (result == mask) {
3128 /* double slash */
3129 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3130 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3131 *cp);
3132 }
3133 result = mask;
3134 break;
3135 case ' ':
3136 break;
3137 default:
3138 if (!isspace((int)*cp)) {
3139 /* reached illegal, non-space character */
3140 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3141 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3142 *cp);
3143 }
3144 break;
3145 }
3146 ++cp;
3147 }
3148
3149 /* check if we reached end of string before '/' character was found */
3150 if (result == high) {
3151 if (*high == 0) {
3152 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3153 }
3154 return parseError(SKUTILS_ERR_SHORT, "Missing '/' character");
3155 }
3156
3157 if (*mask == 0) {
3158 return parseError(SKUTILS_ERR_SHORT,
3159 "Missing masks state flags value");
3160 }
3161
3162 /* make sure high is a proper subset of mask */
3163 if ((*high & *mask) != *high) {
3164 return parseError(SKUTILS_ERR_BAD_RANGE,
3165 ("High state flags is not subset"
3166 " of mask state flags"));
3167 }
3168
3169 /* success */
3170 return SKUTILS_OK;
3171 }
3172
3173
3174 /* parse string as uint32_t. see header for details */
3175 int
skStringParseUint32(uint32_t * result_val,const char * int_string,uint32_t min_val,uint32_t max_val)3176 skStringParseUint32(
3177 uint32_t *result_val,
3178 const char *int_string,
3179 uint32_t min_val,
3180 uint32_t max_val)
3181 {
3182 uint64_t tmp = UINT64_MAX;
3183 int rv;
3184
3185 rv = skStringParseUint64(&tmp, int_string, min_val,
3186 ((max_val == 0) ? UINT32_MAX : max_val));
3187 if (rv >= 0 || rv == SKUTILS_ERR_MINIMUM || rv == SKUTILS_ERR_MAXIMUM){
3188 if (tmp > UINT32_MAX) {
3189 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3190 }
3191 *result_val = UINT32_MAX & (uint32_t)tmp;
3192 }
3193 return rv;
3194 }
3195
3196
3197 /* parse string as uint64_t. see header for details */
3198 int
skStringParseUint64(uint64_t * result_val,const char * int_string,uint64_t min_val,uint64_t max_val)3199 skStringParseUint64(
3200 uint64_t *result_val,
3201 const char *int_string,
3202 uint64_t min_val,
3203 uint64_t max_val)
3204 {
3205 const char *sp;
3206 char *ep;
3207 #if (SK_SIZEOF_LONG >= 8)
3208 #define U64_OVERFLOW ULONG_MAX
3209 unsigned long val;
3210 #else
3211 #define U64_OVERFLOW ULLONG_MAX
3212 unsigned long long val;
3213 #endif
3214
3215 /* check inputs */
3216 assert(result_val);
3217 assert(max_val == 0 || min_val <= max_val);
3218 if (!int_string) {
3219 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3220 }
3221
3222 sp = int_string;
3223
3224 /* ignore leading whitespace */
3225 while (*sp && isspace((int)*sp)) {
3226 ++sp;
3227 }
3228 if ('\0' == *sp) {
3229 /* whitespace only or empty string */
3230 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3231 }
3232
3233 /* number that begins with '-' is not unsigned */
3234 if ('-' == *sp) {
3235 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3236 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3237 *sp);
3238 }
3239
3240 /* parse the string */
3241 errno = 0;
3242 #if (SK_SIZEOF_LONG >= 8)
3243 val = strtoul(sp, &ep, 10);
3244 #else
3245 val = strtoull(sp, &ep, 10);
3246 #endif
3247 if (sp == ep) {
3248 /* parse error */
3249 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3250 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3251 *sp);
3252 }
3253 if (val == U64_OVERFLOW && errno == ERANGE) {
3254 /* overflow */
3255 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3256 }
3257 #if (U64_OVERFLOW > UINT64_MAX)
3258 if (val > UINT64_MAX) {
3259 /* too big */
3260 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3261 }
3262 #endif
3263
3264 *result_val = (uint64_t)val;
3265 if (*result_val < min_val) {
3266 /* too small */
3267 return parseError(SKUTILS_ERR_MINIMUM, ("%s of %" PRIu64),
3268 PARSE_ERRORCODE_MSG(SKUTILS_ERR_MINIMUM),
3269 min_val);
3270 }
3271 if (max_val > 0 && *result_val > max_val) {
3272 /* too big */
3273 return parseError(SKUTILS_ERR_MAXIMUM, ("%s of %" PRIu64),
3274 PARSE_ERRORCODE_MSG(SKUTILS_ERR_MAXIMUM),
3275 max_val);
3276 }
3277
3278 /* ignore trailing whitespace, but only if we reach the end of the
3279 * string. */
3280 sp = ep;
3281 while (*sp && isspace((int)*sp)) {
3282 ++sp;
3283 }
3284 if ('\0' != *sp) {
3285 /* junk at end, return position of 'ep' */
3286 return ep - int_string;
3287 }
3288
3289 return 0;
3290 }
3291
3292
3293 int
skStringParseHumanUint64(uint64_t * result_val,const char * int_string,unsigned int parse_flags)3294 skStringParseHumanUint64(
3295 uint64_t *result_val,
3296 const char *int_string,
3297 unsigned int parse_flags)
3298 {
3299 const char *sp; /* Current parse position */
3300 const char *tp; /* Temporary pointer */
3301 const char *hv; /* Index into sk_human_value_list */
3302 char *ep; /* End of parsed number */
3303 int val_index;
3304 double tmp_val;
3305 struct {
3306 const char c;
3307 double si;
3308 double trad;
3309 } sk_human_values[] = {
3310 {'k', 1.0e3, 1024.0},
3311 {'m', 1.0e6, 1048576.0},
3312 {'g', 1.0e9, 1073741824.0},
3313 {'t', 1.0e12, 1099511627776.0}
3314 };
3315 const char sk_human_value_list[] = "kmgt";
3316
3317 /* check inputs */
3318 assert(result_val);
3319 if (!int_string) {
3320 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3321 }
3322
3323 /* allow parse_flags of 0 to be default */
3324 if (parse_flags == 0) {
3325 parse_flags = SK_HUMAN_NORMAL;
3326 }
3327
3328 sp = int_string;
3329
3330 /* ignore leading whitespace */
3331 while (*sp && isspace((int)*sp)) {
3332 ++sp;
3333 }
3334 if ('\0' == *sp) {
3335 /* whitespace only or empty string */
3336 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3337 }
3338
3339 /* parse the string */
3340 errno = 0;
3341 tmp_val = strtod(sp, &ep);
3342 if (sp == ep) {
3343 /* parse error */
3344 return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3345 }
3346 if (errno == ERANGE) {
3347 if (tmp_val == HUGE_VAL || tmp_val == -HUGE_VAL) {
3348 /* overflow */
3349 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3350 }
3351 return parseError(SKUTILS_ERR_UNDERFLOW, PE_NULL);
3352 }
3353 if (tmp_val < 0) {
3354 /* underflow */
3355 return parseError(SKUTILS_ERR_UNDERFLOW, PE_NULL);
3356 }
3357 if (isnan(tmp_val)) {
3358 /* NAN */
3359 return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3360 }
3361
3362 tp = sp = ep;
3363
3364 /* Possibly eat trailing whitespace (Parse with tp because it
3365 * might be space at the end (no suffix) when we are not supposed
3366 * to parse that.) */
3367 if ((parse_flags & SK_HUMAN_MID_WS)
3368 || !(parse_flags & SK_HUMAN_END_NO_WS))
3369 {
3370 while (*tp && isspace((int)*tp)) {
3371 ++tp;
3372 }
3373 }
3374
3375 /* No suffix? */
3376 if ('\0' == *tp) {
3377 if (!(parse_flags & SK_HUMAN_END_NO_WS)) {
3378 /* If there was no suffix, and we are supposed to parse
3379 * trailing whitespace, set pointer to the end. */
3380 sp = tp;
3381 }
3382 goto parsed;
3383 }
3384
3385 /* Spaces before suffix allowed? */
3386 if ((tp != sp) && !(parse_flags & SK_HUMAN_MID_WS)) {
3387 /* If there is a suffix, and white space in the middle is
3388 * illegal, treat the suffix as junk at the end of the
3389 * input. */
3390 sp = tp;
3391 goto parsed;
3392 }
3393
3394 /* Possible suffix */
3395 hv = strchr(sk_human_value_list, tolower((int)*tp));
3396 if (hv != NULL) {
3397 /* Valid suffix found, set the parse pointer to the end of it */
3398 sp = tp + 1;
3399
3400 /* Find suffix information */
3401 val_index = hv - sk_human_value_list;
3402 assert((int)sk_human_values[val_index].c == tolower((int)*tp));
3403
3404 /* Use suffix value */
3405 if (((parse_flags & SK_HUMAN_LOWER_SI) && islower((int)*tp)) ||
3406 ((parse_flags & SK_HUMAN_UPPER_SI) && isupper((int)*tp)))
3407 {
3408 tmp_val *= sk_human_values[val_index].si;
3409 } else {
3410 tmp_val *= sk_human_values[val_index].trad;
3411 }
3412
3413 /* eat trailing whitespace */
3414 if (!(parse_flags & SK_HUMAN_END_NO_WS)) {
3415 while (*sp && isspace((int)*sp)) {
3416 ++sp;
3417 }
3418 }
3419 } else if (!(parse_flags & SK_HUMAN_END_NO_WS)) {
3420 /* No valid suffix, but we allow trailing spaces. */
3421 sp = tp;
3422 }
3423
3424 parsed:
3425 if (tmp_val > UINT64_MAX) {
3426 /* overflow */
3427 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3428 }
3429
3430 *result_val = (uint64_t)tmp_val;
3431
3432 if ('\0' != *sp) {
3433 /* junk at end */
3434 return 1 + (sp - int_string);
3435 }
3436
3437 return 0;
3438 }
3439
3440
3441 int
skStringParseRange32(uint32_t * range_lower,uint32_t * range_upper,const char * range_string,uint32_t min_val,uint32_t max_val,unsigned int flags)3442 skStringParseRange32(
3443 uint32_t *range_lower,
3444 uint32_t *range_upper,
3445 const char *range_string,
3446 uint32_t min_val,
3447 uint32_t max_val,
3448 unsigned int flags)
3449 {
3450 uint64_t tmp_lower = 0;
3451 uint64_t tmp_upper = 0;
3452 int rv;
3453
3454 rv = skStringParseRange64(&tmp_lower, &tmp_upper, range_string, min_val,
3455 ((max_val == 0) ? UINT32_MAX : max_val), flags);
3456
3457 /* these return codes indicate that at least one value was set */
3458 if (rv >= 0 || rv == SKUTILS_ERR_BAD_RANGE
3459 || rv == SKUTILS_ERR_MINIMUM || rv == SKUTILS_ERR_MAXIMUM)
3460 {
3461 /* return overflow error if appropriate */
3462 if ((tmp_lower > UINT32_MAX) || (tmp_upper > UINT32_MAX)) {
3463 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3464 }
3465 /* convert numbers back to uint32 */
3466 *range_lower = UINT32_MAX & (uint32_t)tmp_lower;
3467 *range_upper = UINT32_MAX & (uint32_t)tmp_upper;
3468 }
3469 return rv;
3470 }
3471
3472
3473 /* parse a single number '3' or a single range '3-5' */
3474 int
skStringParseRange64(uint64_t * range_lower,uint64_t * range_upper,const char * range_string,uint64_t min_val,uint64_t max_val,unsigned int flags)3475 skStringParseRange64(
3476 uint64_t *range_lower,
3477 uint64_t *range_upper,
3478 const char *range_string,
3479 uint64_t min_val,
3480 uint64_t max_val,
3481 unsigned int flags)
3482 {
3483 const char *cp;
3484 int rv;
3485
3486 assert(range_lower);
3487 assert(range_upper);
3488 assert(range_string);
3489
3490 /* parse first part of range; rv, if positive, will be location of
3491 * the first non-digit following the value---should be a hyphen */
3492 rv = skStringParseUint64(range_lower, range_string, min_val, max_val);
3493 if (rv < 0) {
3494 /* an error */
3495 return rv;
3496 }
3497
3498 if (rv == 0) {
3499 /* got a single value */
3500 if (flags & SKUTILS_RANGE_NO_SINGLE) {
3501 /* missing upper half */
3502 return parseError(SKUTILS_ERR_SHORT,
3503 ("Range is missing hyphen"
3504 " (single value is not supported)"));
3505 }
3506 /* single value ok; set upper and return */
3507 if (flags & SKUTILS_RANGE_MAX_SINGLE) {
3508 /* a missing range_upper is always the maximum */
3509 *range_upper = ((max_val == 0) ? UINT64_MAX : max_val);
3510 } else {
3511 /* set range_upper to the same value as lower */
3512 *range_upper = *range_lower;
3513 }
3514 return SKUTILS_OK;
3515 }
3516
3517 /* get the character where parsing stopped---hopefully a hyphen */
3518 cp = &(range_string[rv]);
3519
3520 /* check for the hyphen */
3521 if (*cp != '-') {
3522 /* stopped on non-hyphen */
3523 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3524 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *cp);
3525 }
3526
3527 /* goto start of upper bound */
3528 ++cp;
3529 ++rv;
3530
3531 /* make certain character after '-' is a digit */
3532 if (!isdigit((int)*cp)) {
3533 /* check for open-ended range, permit whitespace between '-'
3534 * and end-of-string */
3535 while (isspace((int)*cp)) {
3536 ++cp;
3537 }
3538 if (*cp == '\0') {
3539 if (flags & SKUTILS_RANGE_NO_OPEN) {
3540 /* missing upper half */
3541 return parseError(SKUTILS_ERR_SHORT,
3542 ("Range is missing its upper limit"
3543 " (open-ended ranges are not supported)"));
3544 }
3545 /* set upper bound to maximum allowed value */
3546 *range_upper = ((max_val == 0) ? UINT64_MAX : max_val);
3547 return SKUTILS_OK;
3548 }
3549 /* got some junk char or embedded whitespace */
3550 return parseError(SKUTILS_ERR_BAD_CHAR,
3551 "%s '%c'",
3552 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3553 range_string[rv]);
3554 }
3555
3556 /* parse upper part of range */
3557 rv = skStringParseUint64(range_upper, cp, min_val, max_val);
3558 if (rv < 0) {
3559 /* parse error */
3560 return rv;
3561 }
3562 if (rv > 0) {
3563 /* extra chars after range */
3564 return parseError(SKUTILS_ERR_BAD_CHAR,
3565 "%s '%c'",
3566 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), cp[rv]);
3567 }
3568
3569 if (*range_upper < *range_lower) {
3570 return parseError(SKUTILS_ERR_BAD_RANGE, PE_NULL);
3571 }
3572
3573 return SKUTILS_OK;
3574 }
3575
3576
3577 /* parse string as a double. see header for details */
3578 int
skStringParseDouble(double * result_val,const char * dbl_string,double min_val,double max_val)3579 skStringParseDouble(
3580 double *result_val,
3581 const char *dbl_string,
3582 double min_val,
3583 double max_val)
3584 {
3585 const char *sp;
3586 char *ep;
3587 double val;
3588
3589 /* check inputs */
3590 assert(result_val);
3591 assert(max_val == 0 || min_val <= max_val);
3592 if (!dbl_string) {
3593 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3594 }
3595
3596 sp = dbl_string;
3597
3598 /* ignore leading whitespace */
3599 while (*sp && isspace((int)*sp)) {
3600 ++sp;
3601 }
3602 if ('\0' == *sp) {
3603 /* whitespace only or empty string */
3604 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3605 }
3606
3607 /* parse the string */
3608 errno = 0;
3609 val = strtod(sp, &ep);
3610 if (sp == ep) {
3611 /* parse error */
3612 return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3613 }
3614 if (errno == ERANGE) {
3615 if (val == 0) {
3616 /* underflow */
3617 return parseError(SKUTILS_ERR_UNDERFLOW, PE_NULL);
3618 }
3619 /* overflow */
3620 assert(val == HUGE_VAL || val == -HUGE_VAL);
3621 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3622 }
3623 if (isnan(val)) {
3624 /* NAN */
3625 return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3626 }
3627
3628 *result_val = val;
3629 if (*result_val < min_val) {
3630 /* too small */
3631 return parseError(SKUTILS_ERR_MINIMUM, "%s of %f",
3632 PARSE_ERRORCODE_MSG(SKUTILS_ERR_MINIMUM),
3633 min_val);
3634 }
3635 if (max_val > 0.0 && *result_val > max_val) {
3636 /* too big */
3637 return parseError(SKUTILS_ERR_MAXIMUM, "%s of %f",
3638 PARSE_ERRORCODE_MSG(SKUTILS_ERR_MAXIMUM),
3639 max_val);
3640 }
3641
3642 /* ignore trailing whitespace, but only if we reach the end of the
3643 * string. */
3644 sp = ep;
3645 while (*sp && isspace((int)*sp)) {
3646 ++sp;
3647 }
3648 if ('\0' != *sp) {
3649 /* junk at end, return position of 'ep' */
3650 return ep - dbl_string;
3651 }
3652
3653 return 0;
3654 }
3655
3656
3657 /* parse string as a range of doubles. see header for details */
3658 int
skStringParseDoubleRange(double * range_lower,double * range_upper,const char * range_string,double min_val,double max_val,unsigned int flags)3659 skStringParseDoubleRange(
3660 double *range_lower,
3661 double *range_upper,
3662 const char *range_string,
3663 double min_val,
3664 double max_val,
3665 unsigned int flags)
3666 {
3667 const char *cp;
3668 int rv;
3669
3670 /* parse first part of range; rv, if positive, will be location of
3671 * the first non-digit following the value---should be a hyphen */
3672 rv = skStringParseDouble(range_lower, range_string, min_val, max_val);
3673 if (rv < 0) {
3674 /* an error */
3675 return rv;
3676 }
3677
3678 if (rv == 0) {
3679 /* got a single value */
3680 if (flags & SKUTILS_RANGE_NO_SINGLE) {
3681 /* missing upper half */
3682 return parseError(SKUTILS_ERR_SHORT,
3683 ("Range is missing hyphen"
3684 " (single value is not supported)"));
3685 }
3686 /* single value ok. set range_upper to the same value and
3687 * return */
3688 *range_upper = *range_lower;
3689 return SKUTILS_OK;
3690 }
3691
3692 /* get the character where parsing stopped---hopefully a hyphen */
3693 cp = &(range_string[rv]);
3694
3695 /* check for the hyphen */
3696 if (*cp != '-') {
3697 /* stopped on non-hyphen */
3698 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3699 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *cp);
3700 }
3701
3702 /* goto start of upper bound */
3703 ++cp;
3704 ++rv;
3705
3706 /* if *cp is on a '+' or '-', make certain the following character
3707 * is a digit. Otherwise, make certain we're on a digit, or
3708 * handle an open-ended range. */
3709 if (*cp == '+' || *cp == '-') {
3710 if (!isdigit((int) *(cp + 1))) {
3711 return parseError(SKUTILS_ERR_BAD_CHAR,
3712 "%s '%c'",
3713 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3714 range_string[rv]);
3715 }
3716
3717 } else if (!isdigit((int)*cp)) {
3718 /* check for open-ended range, permit whitespace between '-'
3719 * and end-of-string */
3720 while (isspace((int)*cp)) {
3721 ++cp;
3722 }
3723 if (*cp == '\0') {
3724 if (flags & SKUTILS_RANGE_NO_OPEN) {
3725 /* missing upper half */
3726 return parseError(SKUTILS_ERR_SHORT,
3727 ("Range is missing its upper limit"
3728 " (open-ended ranges are not supported)"));
3729 }
3730 /* set upper bound to maximum allowed value */
3731 *range_upper = ((max_val == 0.0) ? HUGE_VAL : max_val);
3732 return SKUTILS_OK;
3733 }
3734 /* got some junk char or embedded whitespace */
3735 return parseError(SKUTILS_ERR_BAD_CHAR,
3736 "%s '%c'",
3737 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3738 range_string[rv]);
3739 }
3740
3741 /* parse upper part of range */
3742 rv = skStringParseDouble(range_upper, cp, min_val, max_val);
3743 if (rv < 0) {
3744 /* parse error */
3745 return rv;
3746 }
3747 if (rv > 0) {
3748 /* extra chars after range */
3749 return parseError(SKUTILS_ERR_BAD_CHAR,
3750 "%s '%c'",
3751 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), cp[rv]);
3752 }
3753
3754 if (*range_upper < *range_lower) {
3755 return parseError(SKUTILS_ERR_BAD_RANGE, PE_NULL);
3756 }
3757
3758 return SKUTILS_OK;
3759 }
3760
3761
3762 const char *
skSignalToName(int signal_num)3763 skSignalToName(
3764 int signal_num)
3765 {
3766 int i;
3767
3768 for (i = 0; i < signal_name2num_count; ++i) {
3769 if (signal_num == signal_name2num[i].number) {
3770 return signal_name2num[i].name;
3771 }
3772 }
3773 return "?";
3774 }
3775
3776
3777 int
skStringParseSignal(int * signal_num,const char * signal_name)3778 skStringParseSignal(
3779 int *signal_num,
3780 const char *signal_name)
3781 {
3782 char buf[16];
3783 const char *sp = signal_name;
3784 const char *ep;
3785 int i;
3786
3787 /* check inputs */
3788 assert(signal_num);
3789 if (signal_name == NULL) {
3790 return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3791 }
3792
3793 /* ignore leading whitespace */
3794 while (*sp && isspace((int)*sp)) {
3795 ++sp;
3796 }
3797 if ('\0' == *sp) {
3798 /* whitespace only or empty string */
3799 return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3800 }
3801
3802 /* if it looks like a number, treat it as such */
3803 if (isdigit((int)*sp)) {
3804 uint32_t tmp32 = 0;
3805 int max_sig = 0;
3806 int rv;
3807
3808 for (i = 0; i < signal_name2num_count; ++i) {
3809 if (max_sig < signal_name2num[i].number) {
3810 max_sig = signal_name2num[i].number;
3811 }
3812 }
3813
3814 rv = skStringParseUint32(&tmp32, signal_name, 1, max_sig);
3815 /* should we search for 'tmp32' in signal_name2num[] to
3816 * determine whether it is a usable value? */
3817 *signal_num = (int)tmp32;
3818 return rv;
3819 }
3820
3821 /* skip leading "SIG" prefix, if any */
3822 if (0 == strncmp("SIG", sp, 3)) {
3823 sp += 3;
3824 }
3825
3826 /* find end of signal name. if extra text follows name, copy name
3827 * into 'buf'. */
3828 ep = sp;
3829 while (isalnum((int)*ep)) {
3830 ++ep;
3831 }
3832 if (ep == sp) {
3833 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3834 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
3835 }
3836 if ('\0' != *ep) {
3837 if ((ep - sp) > (int)(sizeof(buf) - 1)) {
3838 /* name too long */
3839 return parseError(SKUTILS_ERR_BAD_CHAR,
3840 "Value too long to be valid signal name");
3841 }
3842 strncpy(buf, sp, sizeof(buf));
3843 buf[ep - sp] = '\0';
3844 sp = buf;
3845 }
3846
3847 /* linear search to find a match */
3848 for (i = 0; i < signal_name2num_count; ++i) {
3849 if (0 == strcasecmp(sp, signal_name2num[i].name)) {
3850 /* found a match */
3851 *signal_num = signal_name2num[i].number;
3852 while (isspace((int)*ep)) {
3853 ++ep;
3854 }
3855 if ('\0' == *ep) {
3856 return 0;
3857 }
3858 return (ep - signal_name);
3859 }
3860 }
3861
3862 return parseError(SKUTILS_ERR_BAD_CHAR, "Unknown signal name '%s'", sp);
3863 }
3864
3865
3866 /*
3867 ** Local Variables:
3868 ** mode:c
3869 ** indent-tabs-mode:nil
3870 ** c-basic-offset:4
3871 ** End:
3872 */
3873