aboutsummaryrefslogtreecommitdiffstats
path: root/smtpd/parser.c
diff options
context:
space:
mode:
authorGilles Chehade <gilles@rentabiliweb.com>2014-01-20 10:00:19 +0100
committerGilles Chehade <gilles@rentabiliweb.com>2014-01-20 10:00:19 +0100
commit72a2b4822d2f02a0f3cada6b918028b3f0af8ef9 (patch)
treef467c5e137f8da25352ccfe81f92c6b6bf958db5 /smtpd/parser.c
parentMerge branch 'master' into portable (diff)
parentImplement a mechanism by which the admin can forbid the mta to (diff)
downloadOpenSMTPD-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.c85
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);
+}