diff options
author | 2014-01-20 10:00:19 +0100 | |
---|---|---|
committer | 2014-01-20 10:00:19 +0100 | |
commit | 72a2b4822d2f02a0f3cada6b918028b3f0af8ef9 (patch) | |
tree | f467c5e137f8da25352ccfe81f92c6b6bf958db5 /smtpd/parser.c | |
parent | Merge branch 'master' into portable (diff) | |
parent | Implement a mechanism by which the admin can forbid the mta to (diff) | |
download | OpenSMTPD-72a2b4822d2f02a0f3cada6b918028b3f0af8ef9.tar.xz OpenSMTPD-72a2b4822d2f02a0f3cada6b918028b3f0af8ef9.zip |
Merge branch 'master' into portableopensmtpd-201401201010p1
Conflicts:
smtpd/table_redis.c
Diffstat (limited to 'smtpd/parser.c')
-rw-r--r-- | smtpd/parser.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/smtpd/parser.c b/smtpd/parser.c index 39dd7713..3c0a45e3 100644 --- a/smtpd/parser.c +++ b/smtpd/parser.c @@ -20,10 +20,16 @@ #include <sys/types.h> #include <sys/queue.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> +#include <arpa/inet.h> #include <err.h> #include <inttypes.h> #include <limits.h> +#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -44,6 +50,8 @@ struct node { static struct node *root; +static int text_to_sockaddr(struct sockaddr *, int, const char *); + #define ARGVMAX 64 int @@ -92,6 +100,8 @@ cmd_install(const char *pattern, int (*cmd)(int, struct parameter*)) tmp->type = P_EVPID; else if (!strcmp(argv[i], "<routeid>")) tmp->type = P_ROUTEID; + else if (!strcmp(argv[i], "<addr>")) + tmp->type = P_ADDR; else tmp->type = P_TOKEN; tmp->token = strdup(argv[i]); @@ -166,6 +176,11 @@ cmd_check(const char *str, struct node *node, struct parameter *res) return (0); return (1); + case P_ADDR: + if (text_to_sockaddr((struct sockaddr *)&res->u.u_ss, PF_UNSPEC, str) == 0) + return (1); + return (0); + default: errx(1, "bad token type: %d", node->type); return (0); @@ -259,3 +274,73 @@ cmd_show_params(int argc, struct parameter *argv) printf ("\n"); return (1); } + +static int +text_to_sockaddr(struct sockaddr *sa, int family, const char *str) +{ + struct in_addr ina; + struct in6_addr in6a; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + char *cp, *str2; + const char *errstr; + + switch (family) { + case PF_UNSPEC: + if (text_to_sockaddr(sa, PF_INET, str) == 0) + return (0); + return text_to_sockaddr(sa, PF_INET6, str); + + case PF_INET: + if (inet_pton(PF_INET, str, &ina) != 1) + return (-1); + + sin = (struct sockaddr_in *)sa; + memset(sin, 0, sizeof *sin); + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_family = PF_INET; + sin->sin_addr.s_addr = ina.s_addr; + return (0); + + case PF_INET6: + cp = strchr(str, SCOPE_DELIMITER); + if (cp) { + str2 = strdup(str); + if (str2 == NULL) + return (-1); + str2[cp - str] = '\0'; + if (inet_pton(PF_INET6, str2, &in6a) != 1) { + free(str2); + return (-1); + } + cp++; + free(str2); + } else if (inet_pton(PF_INET6, str, &in6a) != 1) + return (-1); + + sin6 = (struct sockaddr_in6 *)sa; + memset(sin6, 0, sizeof *sin6); + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_family = PF_INET6; + sin6->sin6_addr = in6a; + + if (cp == NULL) + return (0); + + if (IN6_IS_ADDR_LINKLOCAL(&in6a) || + IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || + IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + if ((sin6->sin6_scope_id = if_nametoindex(cp))) + return (0); + + sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); + if (errstr) + return (-1); + return (0); + + default: + break; + } + + return (-1); +} |