addrmatch.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* $OpenBSD: addrmatch.c,v 1.14 2018/07/31 03:07:24 djm Exp $ */
  2. /*
  3. * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "includes.h"
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <arpa/inet.h>
  22. #include <netdb.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <stdarg.h>
  27. #include "addr.h"
  28. #include "match.h"
  29. #include "log.h"
  30. /*
  31. * Match "addr" against list pattern list "_list", which may contain a
  32. * mix of CIDR addresses and old-school wildcards.
  33. *
  34. * If addr is NULL, then no matching is performed, but _list is parsed
  35. * and checked for well-formedness.
  36. *
  37. * Returns 1 on match found (never returned when addr == NULL).
  38. * Returns 0 on if no match found, or no errors found when addr == NULL.
  39. * Returns -1 on negated match found (never returned when addr == NULL).
  40. * Returns -2 on invalid list entry.
  41. */
  42. int
  43. addr_match_list(const char *addr, const char *_list)
  44. {
  45. char *list, *cp, *o;
  46. struct xaddr try_addr, match_addr;
  47. u_int masklen, neg;
  48. int ret = 0, r;
  49. if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
  50. debug2("%s: couldn't parse address %.100s", __func__, addr);
  51. return 0;
  52. }
  53. if ((o = list = strdup(_list)) == NULL)
  54. return -1;
  55. while ((cp = strsep(&list, ",")) != NULL) {
  56. neg = *cp == '!';
  57. if (neg)
  58. cp++;
  59. if (*cp == '\0') {
  60. ret = -2;
  61. break;
  62. }
  63. /* Prefer CIDR address matching */
  64. r = addr_pton_cidr(cp, &match_addr, &masklen);
  65. if (r == -2) {
  66. debug2("%s: inconsistent mask length for "
  67. "match network \"%.100s\"", __func__, cp);
  68. ret = -2;
  69. break;
  70. } else if (r == 0) {
  71. if (addr != NULL && addr_netmatch(&try_addr,
  72. &match_addr, masklen) == 0) {
  73. foundit:
  74. if (neg) {
  75. ret = -1;
  76. break;
  77. }
  78. ret = 1;
  79. }
  80. continue;
  81. } else {
  82. /* If CIDR parse failed, try wildcard string match */
  83. if (addr != NULL && match_pattern(addr, cp) == 1)
  84. goto foundit;
  85. }
  86. }
  87. free(o);
  88. return ret;
  89. }
  90. /*
  91. * Match "addr" against list CIDR list "_list". Lexical wildcards and
  92. * negation are not supported. If "addr" == NULL, will verify structure
  93. * of "_list".
  94. *
  95. * Returns 1 on match found (never returned when addr == NULL).
  96. * Returns 0 on if no match found, or no errors found when addr == NULL.
  97. * Returns -1 on error
  98. */
  99. int
  100. addr_match_cidr_list(const char *addr, const char *_list)
  101. {
  102. char *list, *cp, *o;
  103. struct xaddr try_addr, match_addr;
  104. u_int masklen;
  105. int ret = 0, r;
  106. if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
  107. debug2("%s: couldn't parse address %.100s", __func__, addr);
  108. return 0;
  109. }
  110. if ((o = list = strdup(_list)) == NULL)
  111. return -1;
  112. while ((cp = strsep(&list, ",")) != NULL) {
  113. if (*cp == '\0') {
  114. error("%s: empty entry in list \"%.100s\"",
  115. __func__, o);
  116. ret = -1;
  117. break;
  118. }
  119. /*
  120. * NB. This function is called in pre-auth with untrusted data,
  121. * so be extra paranoid about junk reaching getaddrino (via
  122. * addr_pton_cidr).
  123. */
  124. /* Stop junk from reaching getaddrinfo. +3 is for masklen */
  125. if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
  126. error("%s: list entry \"%.100s\" too long",
  127. __func__, cp);
  128. ret = -1;
  129. break;
  130. }
  131. #define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
  132. if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
  133. error("%s: list entry \"%.100s\" contains invalid "
  134. "characters", __func__, cp);
  135. ret = -1;
  136. }
  137. /* Prefer CIDR address matching */
  138. r = addr_pton_cidr(cp, &match_addr, &masklen);
  139. if (r == -1) {
  140. error("Invalid network entry \"%.100s\"", cp);
  141. ret = -1;
  142. break;
  143. } else if (r == -2) {
  144. error("Inconsistent mask length for "
  145. "network \"%.100s\"", cp);
  146. ret = -1;
  147. break;
  148. } else if (r == 0 && addr != NULL) {
  149. if (addr_netmatch(&try_addr, &match_addr,
  150. masklen) == 0)
  151. ret = 1;
  152. continue;
  153. }
  154. }
  155. free(o);
  156. return ret;
  157. }