7 /* generate patterns for my own interface addresses
9 /* #include <mynetworks.h>
11 /* const char *mynetworks()
13 /* This routine uses the address list built by own_inet_addr()
14 /* to produce a list of patterns that match the corresponding
17 /* The interface list is specified with the "inet_interfaces"
18 /* configuration parameter.
20 /* The address to netblock conversion style is specified with
21 /* the "mynetworks_style" parameter: one of "class" (match
22 /* whole class A, B, C or D networks), "subnet" (match local
23 /* subnets), or "host" (match local interfaces only).
27 /* The Secure Mailer license must be distributed with this software.
30 /* IBM T.J. Watson Research
32 /* Yorktown Heights, NY 10598, USA
35 /* Department ICT Services
36 /* Eindhoven University of Technology
38 /* 5600 MB Eindhoven, Netherlands
39 /* E-mail: <dean@ipnet6.org>
45 #include <sys/param.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
50 #define IN_CLASSD_NET 0xf0000000
51 #define IN_CLASSD_NSHIFT 28
54 /* Utility library. */
58 #include <inet_addr_list.h>
59 #include <name_mask.h>
60 #include <myaddrinfo.h>
61 #include <mask_addr.h>
66 #include <own_inet_addr.h>
67 #include <mail_params.h>
68 #include <mynetworks.h>
69 #include <sock_addr.h>
70 #include <been_here.h>
72 /* Application-specific. */
74 #define MASK_STYLE_CLASS (1 << 0)
75 #define MASK_STYLE_SUBNET (1 << 1)
76 #define MASK_STYLE_HOST (1 << 2)
78 static const NAME_MASK mask_styles
[] = {
79 MYNETWORKS_STYLE_CLASS
, MASK_STYLE_CLASS
,
80 MYNETWORKS_STYLE_SUBNET
, MASK_STYLE_SUBNET
,
81 MYNETWORKS_STYLE_HOST
, MASK_STYLE_HOST
,
85 /* mynetworks - return patterns that match my own networks */
87 const char *mynetworks(void)
89 static VSTRING
*result
;
92 const char *myname
= "mynetworks";
93 INET_ADDR_LIST
*my_addr_list
;
94 INET_ADDR_LIST
*my_mask_list
;
99 struct sockaddr_storage
*sa
;
100 struct sockaddr_storage
*ma
;
101 int net_mask_count
= 0;
103 BH_TABLE
*dup_filter
;
106 mask_style
= name_mask("mynetworks mask style", mask_styles
,
107 var_mynetworks_style
);
110 * XXX Workaround: name_mask() needs a flags argument so that we can
111 * require exactly one value, or we need to provide an API that is
112 * dedicated for single-valued flags.
114 for (i
= 0, junk
= mask_style
; junk
!= 0; junk
>>= 1U)
117 msg_fatal("bad %s value: %s; specify exactly one value",
118 VAR_MYNETWORKS_STYLE
, var_mynetworks_style
);
120 result
= vstring_alloc(20);
121 my_addr_list
= own_inet_addr_list();
122 my_mask_list
= own_inet_mask_list();
124 for (sa
= my_addr_list
->addrs
, ma
= my_mask_list
->addrs
;
125 sa
< my_addr_list
->addrs
+ my_addr_list
->used
;
131 if (SOCK_ADDR_FAMILY(sa
) == AF_INET
) {
132 addr
= ntohl(SOCK_ADDR_IN_ADDR(sa
).s_addr
);
133 mask
= ntohl(SOCK_ADDR_IN_ADDR(ma
).s_addr
);
135 switch (mask_style
) {
138 * Natural mask. This is dangerous if you're customer of
139 * an ISP who gave you a small portion of their network.
141 case MASK_STYLE_CLASS
:
142 if (IN_CLASSA(addr
)) {
143 mask
= IN_CLASSA_NET
;
144 shift
= IN_CLASSA_NSHIFT
;
145 } else if (IN_CLASSB(addr
)) {
146 mask
= IN_CLASSB_NET
;
147 shift
= IN_CLASSB_NSHIFT
;
148 } else if (IN_CLASSC(addr
)) {
149 mask
= IN_CLASSC_NET
;
150 shift
= IN_CLASSC_NSHIFT
;
151 } else if (IN_CLASSD(addr
)) {
152 mask
= IN_CLASSD_NET
;
153 shift
= IN_CLASSD_NSHIFT
;
155 msg_fatal("%s: unknown address class: %s",
156 myname
, inet_ntoa(SOCK_ADDR_IN_ADDR(sa
)));
161 * Subnet mask. This is less unsafe, but still bad if
162 * you're connected to a large subnet.
164 case MASK_STYLE_SUBNET
:
165 for (junk
= mask
, shift
= MAI_V4ADDR_BITS
; junk
!= 0;
171 * Host only. Do not relay authorize other hosts.
173 case MASK_STYLE_HOST
:
179 msg_panic("unknown mynetworks mask style: %s",
180 var_mynetworks_style
);
182 net
.s_addr
= htonl(addr
& mask
);
183 vstring_sprintf_append(result
, "%s/%d ",
184 inet_ntoa(net
), MAI_V4ADDR_BITS
- shift
);
189 else if (SOCK_ADDR_FAMILY(sa
) == AF_INET6
) {
190 MAI_HOSTADDR_STR hostaddr
;
194 struct sockaddr_in6 net6
;
196 switch (mask_style
) {
199 * There are no classes for IPv6. We default to subnets
202 case MASK_STYLE_CLASS
:
209 case MASK_STYLE_SUBNET
:
210 ac
= (unsigned char *) &SOCK_ADDR_IN6_ADDR(ma
);
211 end
= ac
+ sizeof(SOCK_ADDR_IN6_ADDR(ma
));
212 shift
= MAI_V6ADDR_BITS
;
214 if ((ch
= *ac
++) == (unsigned char) -1) {
226 * Host only. Do not relay authorize other hosts.
228 case MASK_STYLE_HOST
:
233 msg_panic("unknown mynetworks mask style: %s",
234 var_mynetworks_style
);
236 /* FIX 200501: IPv6 patch did not clear host bits. */
237 net6
= *SOCK_ADDR_IN6_PTR(sa
);
238 mask_addr((unsigned char *) &net6
.sin6_addr
,
239 sizeof(net6
.sin6_addr
),
240 MAI_V6ADDR_BITS
- shift
);
241 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(&net6
), SOCK_ADDR_LEN(&net6
),
242 &hostaddr
, (MAI_SERVPORT_STR
*) 0, 0);
243 vstring_sprintf_append(result
, "[%s]/%d ",
244 hostaddr
.buf
, MAI_V6ADDR_BITS
- shift
);
250 msg_warn("%s: skipping unknown address family %d",
251 myname
, SOCK_ADDR_FAMILY(sa
));
257 * FIX 200501 IPv6 patch produced repeated results. Some systems
258 * report the same interface multiple times, notably multi-homed
259 * systems with IPv6 link-local or site-local addresses. A
260 * straight-forward sort+uniq produces ugly results, though. Instead
261 * we preserve the original order and use a duplicate filter to
262 * suppress repeated information.
264 if (net_mask_count
> 1) {
265 argv
= argv_split(vstring_str(result
), " ");
266 VSTRING_RESET(result
);
267 dup_filter
= been_here_init(net_mask_count
, BH_FLAG_NONE
);
268 for (cpp
= argv
->argv
; cpp
< argv
->argv
+ argv
->argc
; cpp
++)
269 if (!been_here_fixed(dup_filter
, *cpp
))
270 vstring_sprintf_append(result
, "%s ", *cpp
);
272 been_here_free(dup_filter
);
275 msg_info("%s: %s", myname
, vstring_str(result
));
277 return (vstring_str(result
));
281 #include <inet_proto.h>
283 char *var_inet_interfaces
;
284 char *var_mynetworks_style
;
286 int main(int argc
, char **argv
)
288 INET_PROTO_INFO
*proto_info
;
291 msg_fatal("usage: %s protocols mask_style interface_list (e.g. \"all subnet all\")",
294 proto_info
= inet_proto_init(argv
[0], argv
[1]);
295 var_mynetworks_style
= argv
[2];
296 var_inet_interfaces
= argv
[3];