%token <command> COMMAND /* absolute pathname w/ optional args */
%token <string> ALIAS /* an UPPERCASE alias name */
%token <string> DEFVAR /* a Defaults variable name */
-%token <string> NTWKADDR /* w.x.y.z */
+%token <string> NTWKADDR /* ipv4 or ipv6 address */
%token <string> NETGROUP /* a netgroup (+NAME) */
%token <string> USERGROUP /* a usergroup (%NAME) */
%token <string> WORD /* a word */
load_interfaces()
{
struct ifaddrs *ifa, *ifaddrs;
- /* XXX - sockaddr_in6 sin6; */
struct sockaddr_in *sin;
+#ifdef AF_INET6
+ struct sockaddr_in6 *sin6;
+#endif
int i;
if (getifaddrs(&ifaddrs))
continue;
switch(ifa->ifa_addr->sa_family) {
- /* XXX - AF_INET6 */
case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
num_interfaces++;
break;
}
continue;
switch(ifa->ifa_addr->sa_family) {
- /* XXX - AF_INET6 */
case AF_INET:
sin = (struct sockaddr_in *)ifa->ifa_addr;
memcpy(&interfaces[i].addr, &sin->sin_addr,
sin = (struct sockaddr_in *)ifa->ifa_netmask;
memcpy(&interfaces[i].netmask, &sin->sin_addr,
sizeof(struct in_addr));
+ interfaces[i].family = AF_INET;
i++;
break;
+#ifdef AF_INET6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ memcpy(&interfaces[i].addr, &sin6->sin6_addr,
+ sizeof(struct in6_addr));
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
+ memcpy(&interfaces[i].netmask, &sin6->sin6_addr,
+ sizeof(struct in6_addr));
+ interfaces[i].family = AF_INET6;
+ i++;
+ break;
+#endif /* AF_INET6 */
}
}
#ifdef HAVE_FREEIFADDRS
}
/* Only now can we be sure it was a good/interesting interface. */
+ interfaces[num_interfaces].family = AF_INET;
num_interfaces++;
}
dump_interfaces()
{
int i;
+#ifdef AF_INET6
+ char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN];
+#endif
puts("Local IP address and netmask pairs:");
- for (i = 0; i < num_interfaces; i++)
- printf("\t%s / 0x%x\n", inet_ntoa(interfaces[i].addr),
- (unsigned int)ntohl(interfaces[i].netmask.s_addr));
+ for (i = 0; i < num_interfaces; i++) {
+ switch(interfaces[i].family) {
+ case AF_INET:
+ printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4));
+ puts(inet_ntoa(interfaces[i].netmask.ip4));
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ inet_ntop(AF_INET6, &interfaces[i].addr.ip6,
+ addrbuf, sizeof(addrbuf));
+ inet_ntop(AF_INET6, &interfaces[i].netmask.ip6,
+ maskbuf, sizeof(maskbuf));
+ printf("\t%s / %s\n", addrbuf, maskbuf);
+ break;
+#endif /* AF_INET6 */
+ }
+ }
}
* IP address and netmask pairs for checking against local interfaces.
*/
struct interface {
- struct in_addr addr;
- struct in_addr netmask;
+ int family; /* AF_INET or AF_INET6 */
+ union {
+ struct in_addr ip4;
+#ifdef AF_INET6
+ struct in6_addr ip6;
+#endif
+ } addr;
+ union {
+ struct in_addr ip4;
+#ifdef AF_INET6
+ struct in6_addr ip6;
+#endif
+ } netmask;
};
/*
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef STDC_HEADERS
}
}
-/*
- * Returns TRUE if "n" is one of our ip addresses or if
- * "n" is a network that we are on, else returns FALSE.
- */
-int
-addr_matches(n)
+static int
+addr_matches_if(n)
char *n;
{
int i;
+ struct in_addr addr;
+ struct interface *ifp;
+#ifdef AF_INET6
+ struct in6_addr addr6;
+ int j;
+#endif
+ int family = AF_UNSPEC;
+
+#ifdef AF_INET6
+ if (inet_pton(AF_INET6, n, &addr6) > 0) {
+ family = AF_INET6;
+ } else
+#else
+ {
+ family = AF_INET;
+ addr.s_addr = inet_addr(n);
+ }
+#endif
+
+ for (i = 0; i < num_interfaces; i++) {
+ ifp = &interfaces[i];
+ if (ifp->family != family)
+ continue;
+ switch(family) {
+ case AF_INET:
+ if (ifp->addr.ip4.s_addr == addr.s_addr ||
+ (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
+ == addr.s_addr)
+ return(TRUE);
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
+ sizeof(addr6.s6_addr)) == 0)
+ return(TRUE);
+ for (j = 0; j < sizeof(addr6.s6_addr); j++) {
+ if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
+ break;
+ }
+ if (j == sizeof(addr6.s6_addr))
+ return(TRUE);
+#endif
+ }
+ }
+
+ return(FALSE);
+}
+
+static int
+addr_matches_if_netmask(n, m)
+ char *n;
char *m;
+{
+ int i;
struct in_addr addr, mask;
+ struct interface *ifp;
+#ifdef AF_INET6
+ struct in6_addr addr6, mask6;
+ int j;
+#endif
+ int family = AF_UNSPEC;
- /* If there's an explicit netmask, use it. */
- if ((m = strchr(n, '/'))) {
- *m++ = '\0';
+#ifdef AF_INET6
+ if (inet_pton(AF_INET6, n, &addr6) > 0)
+ family = AF_INET6;
+ else
+#else
+ {
+ family = AF_INET;
addr.s_addr = inet_addr(n);
+ }
+#endif
+
+ if (family == AF_INET) {
if (strchr(m, '.'))
mask.s_addr = inet_addr(m);
else {
mask.s_addr <<= i;
mask.s_addr = htonl(mask.s_addr);
}
- *(m - 1) = '/';
-
- for (i = 0; i < num_interfaces; i++)
- if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
- return(TRUE);
- } else {
- addr.s_addr = inet_addr(n);
-
- for (i = 0; i < num_interfaces; i++)
- if (interfaces[i].addr.s_addr == addr.s_addr ||
- (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
- == addr.s_addr)
- return(TRUE);
+ }
+#ifdef AF_INET6
+ else {
+ if (inet_pton(AF_INET6, m, &mask6) <= 0) {
+ j = atoi(m);
+ for (i = 0; i < 16; i++) {
+ if (j < i * 8)
+ mask6.s6_addr[i] = 0;
+ else if (i * 8 + 8 <= j)
+ mask6.s6_addr[i] = 0xff;
+ else
+ mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
+ }
+ }
+ }
+#endif /* AF_INET6 */
+
+ for (i = 0; i < num_interfaces; i++) {
+ ifp = &interfaces[i];
+ if (ifp->family != family)
+ continue;
+ switch(family) {
+ case AF_INET:
+ if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
+ return(TRUE);
+#ifdef AF_INET6
+ case AF_INET6:
+ for (j = 0; j < sizeof(addr6.s6_addr); j++) {
+ if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
+ break;
+ }
+ if (j == sizeof(addr6.s6_addr))
+ return(TRUE);
+#endif /* AF_INET6 */
+ }
}
return(FALSE);
}
+/*
+ * Returns TRUE if "n" is one of our ip addresses or if
+ * "n" is a network that we are on, else returns FALSE.
+ */
+int
+addr_matches(n)
+ char *n;
+{
+ char *m;
+ int retval;
+
+ /* If there's an explicit netmask, use it. */
+ if ((m = strchr(n, '/'))) {
+ *m++ = '\0';
+ retval = addr_matches_if_netmask(n, m);
+ *(m - 1) = '/';
+ } else
+ retval = addr_matches_if(n);
+
+ return(retval);
+}
+
/*
* Returns TRUE if the hostname matches the pattern, else FALSE
*/
B<sudo> will query each of the local host's network interfaces and,
if the network number corresponds to one of the hosts's network
interfaces, the corresponding netmask will be used. The netmask
-may be specified either in dotted quad notation (e.g.E<nbsp>255.255.255.0)
-or CIDR notation (number of bits, e.g.E<nbsp>24). A hostname may
+may be specified either in standard IP address notation
+(e.g.E<nbsp>255.255.255.0 or ffff:ffff:ffff:ffff::),
+or CIDR notation (number of bits, e.g.E<nbsp>24 or 64). A hostname may
include shell-style wildcards (see the L<Wildcards> section below),
but unless the C<hostname> command on your machine returns the fully
qualified hostname, you'll need to use the I<fqdn> option for
#endif
%}
+HEXDIGIT [0-9A-Fa-f]{1,4}
OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
DOTTEDQUAD {OCTET}(\.{OCTET}){3}
+IPV6ADDR \:\:|({HEXDIGIT}\:){7}{HEXDIGIT}|({HEXDIGIT}\:){5}{HEXDIGIT}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,7}\:|({HEXDIGIT}\:){1,6}(\:{HEXDIGIT}){1}|({HEXDIGIT}\:){1,5}(\:{HEXDIGIT}){2}|({HEXDIGIT}\:){1,2}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,4}(\:{HEXDIGIT}){3}|({HEXDIGIT}\:){1,4}(\:{HEXDIGIT}){1}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,3}(\:{HEXDIGIT}){4}|({HEXDIGIT}\:){1,3}(\:{HEXDIGIT}){2}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,2}(\:{HEXDIGIT}){5}|({HEXDIGIT}\:){1,2}(\:{HEXDIGIT}){3}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1}(\:{HEXDIGIT}){6}|({HEXDIGIT}\:){1}(\:{HEXDIGIT}){4}\:{DOTTEDQUAD}|\:(\:{HEXDIGIT}){1,7}|\:(\:{HEXDIGIT}){1,5}\:{DOTTEDQUAD}
+
HOSTNAME [[:alnum:]_-]+
WORD ([^#>!=:,\(\) \t\n\\]|\\[^\n])+
PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+
return(NTWKADDR);
}
+{IPV6ADDR}(\/{IPV6ADDR})? {
+ if (!fill(yytext, yyleng))
+ yyterminate();
+ LEXTRACE("NTWKADDR ");
+ return(NTWKADDR);
+ }
+
+{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
+ if (!fill(yytext, yyleng))
+ yyterminate();
+ LEXTRACE("NTWKADDR ");
+ return(NTWKADDR);
+ }
+
<INITIAL>\( {
BEGIN GOTRUNAS;
LEXTRACE("RUNAS ");