summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/pfctl/parse.y140
1 files changed, 138 insertions, 2 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index b9a3e449737..a0a83c37930 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.38 2001/10/01 17:58:16 markus Exp $ */
+/* $OpenBSD: parse.y,v 1.39 2001/10/07 11:56:57 dhartmei Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -38,6 +38,8 @@
#include <arpa/inet.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <ifaddrs.h>
#include <netdb.h>
#include <stdarg.h>
#include <errno.h>
@@ -121,6 +123,10 @@ struct sym *symhead = NULL;
int symset(char *name, char *val);
char * symget(char *name);
+struct ifaddrs *ifa0_lookup(char *ifa_name);
+struct ifaddrs *ifa4_lookup(char *ifa_name);
+struct ifaddrs *ifa6_lookup(char *ifa_name);
+
typedef struct {
union {
u_int32_t number;
@@ -409,8 +415,41 @@ host : address {
address : STRING {
struct hostent *hp;
+ struct ifaddrs *ifa;
+
+ if (ifa0_lookup($1)) {
+ /* an interface with this name exists */
+ if ((ifa = ifa4_lookup($1))) {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in *)
+ ifa->ifa_addr;
- if ((hp = gethostbyname2($1, AF_INET)) == NULL) {
+ $$ = calloc(1,
+ sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "address: calloc");
+ $$->af = AF_INET;
+ memcpy(&$$->addr, &sin->sin_addr,
+ sizeof(u_int32_t));
+ } else if ((ifa = ifa6_lookup($1))) {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)
+ ifa->ifa_addr;
+
+ $$ = calloc(1,
+ sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "address: calloc");
+ $$->af = AF_INET6;
+ memcpy(&$$->addr, &sin6->sin6_addr,
+ sizeof(struct pf_addr));
+ } else {
+ yyerror("interface %s has no IP "
+ "addresses", $1);
+ YYERROR;
+ }
+ }
+ else if ((hp = gethostbyname2($1, AF_INET)) == NULL) {
if ((hp = gethostbyname2($1, AF_INET6))
== NULL) {
yyerror("cannot resolve %s", $1);
@@ -1555,3 +1594,100 @@ symget(char *nam)
return (sym->val);
return (NULL);
}
+
+struct ifaddrs **ifa0tab, **ifa4tab, **ifa6tab;
+int ifa0len, ifa4len, ifa6len;
+
+int
+ifa_comp(const void *p1, const void *p2)
+{
+ struct ifaddrs *ifa1 = *(struct ifaddrs **)p1;
+ struct ifaddrs *ifa2 = *(struct ifaddrs **)p2;
+
+ return strcmp(ifa1->ifa_name, ifa2->ifa_name);
+}
+
+void
+ifa_load(void)
+{
+ struct ifaddrs *ifap, *ifa;
+ int ifalen = 0;
+
+ if (getifaddrs(&ifap) < 0)
+ err(1, "getifaddrs");
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next)
+ ifalen++;
+ /* (over-)allocate tables */
+ ifa0tab = malloc(ifalen * sizeof(void *));
+ ifa4tab = malloc(ifalen * sizeof(void *));
+ ifa6tab = malloc(ifalen * sizeof(void *));
+ if (!ifa0tab || !ifa4tab || !ifa6tab)
+ err(1, "malloc");
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_LINK) {
+ if (bsearch(&ifa, ifa0tab, ifa0len, sizeof(void *),
+ ifa_comp))
+ continue; /* take only the first LINK address */
+ ifa0tab[ifa0len++] = ifa;
+ qsort(ifa0tab, ifa0len, sizeof(void *), ifa_comp);
+ }
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ if (bsearch(&ifa, ifa4tab, ifa4len, sizeof(void *),
+ ifa_comp))
+ continue; /* take only the first IPv4 address */
+ ifa4tab[ifa4len++] = ifa;
+ qsort(ifa4tab, ifa4len, sizeof(void *), ifa_comp);
+ }
+ if (ifa->ifa_addr->sa_family == AF_INET6) {
+ /* XXX - better address selection required! */
+ if (bsearch(&ifa, ifa6tab, ifa6len, sizeof(void *),
+ ifa_comp))
+ continue; /* take only the first IPv6 address */
+ ifa6tab[ifa6len++] = ifa;
+ qsort(ifa6tab, ifa6len, sizeof(void *), ifa_comp);
+ }
+ }
+ /* shrink tables */
+ ifa0tab = realloc(ifa0tab, ifa0len * sizeof(void *));
+ ifa4tab = realloc(ifa4tab, ifa4len * sizeof(void *));
+ ifa6tab = realloc(ifa6tab, ifa6len * sizeof(void *));
+ if (!ifa0tab || !ifa4tab || !ifa6tab)
+ err(1, "realloc");
+}
+
+struct ifaddrs *
+ifa0_lookup(char *ifa_name)
+{
+ struct ifaddrs ifa, *ifp = &ifa, **ifpp;
+
+ if (!ifa0tab)
+ ifa_load();
+ ifa.ifa_name = ifa_name;
+ ifpp = bsearch(&ifp, ifa0tab, ifa0len, sizeof(void *), ifa_comp);
+ return ifpp ? *ifpp : NULL;
+}
+
+struct ifaddrs *
+ifa4_lookup(char *ifa_name)
+{
+ struct ifaddrs ifa, *ifp = &ifa, **ifpp;
+
+ if (!ifa4tab)
+ ifa_load();
+ ifa.ifa_name = ifa_name;
+ ifpp = bsearch(&ifp, ifa4tab, ifa4len, sizeof(void *), ifa_comp);
+ return ifpp ? *ifpp : NULL;
+}
+
+struct ifaddrs *
+ifa6_lookup(char *ifa_name)
+{
+ struct ifaddrs ifa, *ifp = &ifa, **ifpp;
+
+ if (!ifa6tab)
+ ifa_load();
+ ifa.ifa_name = ifa_name;
+ ifpp = bsearch(&ifp, ifa6tab, ifa6len, sizeof(void *), ifa_comp);
+ return ifpp ? *ifpp : NULL;
+}
+