No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / mynetworks.c
blob8c5cf8155d5d3bbf70cf7af46587952f8cbb2858
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* mynetworks 3
6 /* SUMMARY
7 /* generate patterns for my own interface addresses
8 /* SYNOPSIS
9 /* #include <mynetworks.h>
11 /* const char *mynetworks()
12 /* DESCRIPTION
13 /* This routine uses the address list built by own_inet_addr()
14 /* to produce a list of patterns that match the corresponding
15 /* networks.
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).
24 /* LICENSE
25 /* .ad
26 /* .fi
27 /* The Secure Mailer license must be distributed with this software.
28 /* AUTHOR(S)
29 /* Wietse Venema
30 /* IBM T.J. Watson Research
31 /* P.O. Box 704
32 /* Yorktown Heights, NY 10598, USA
34 /* Dean C. Strik
35 /* Department ICT Services
36 /* Eindhoven University of Technology
37 /* P.O. Box 513
38 /* 5600 MB Eindhoven, Netherlands
39 /* E-mail: <dean@ipnet6.org>
40 /*--*/
42 /* System library. */
44 #include <sys_defs.h>
45 #include <sys/param.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
49 #ifndef IN_CLASSD_NET
50 #define IN_CLASSD_NET 0xf0000000
51 #define IN_CLASSD_NSHIFT 28
52 #endif
54 /* Utility library. */
56 #include <msg.h>
57 #include <vstring.h>
58 #include <inet_addr_list.h>
59 #include <name_mask.h>
60 #include <myaddrinfo.h>
61 #include <mask_addr.h>
62 #include <argv.h>
64 /* Global library. */
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;
91 if (result == 0) {
92 const char *myname = "mynetworks";
93 INET_ADDR_LIST *my_addr_list;
94 INET_ADDR_LIST *my_mask_list;
95 unsigned shift;
96 unsigned junk;
97 int i;
98 unsigned mask_style;
99 struct sockaddr_storage *sa;
100 struct sockaddr_storage *ma;
101 int net_mask_count = 0;
102 ARGV *argv;
103 BH_TABLE *dup_filter;
104 char **cpp;
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)
115 i += (junk & 1);
116 if (i != 1)
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;
126 sa++, ma++) {
127 unsigned long addr;
128 unsigned long mask;
129 struct in_addr net;
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;
154 } else {
155 msg_fatal("%s: unknown address class: %s",
156 myname, inet_ntoa(SOCK_ADDR_IN_ADDR(sa)));
158 break;
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;
166 shift--, junk <<= 1)
167 /* void */ ;
168 break;
171 * Host only. Do not relay authorize other hosts.
173 case MASK_STYLE_HOST:
174 mask = ~0;
175 shift = 0;
176 break;
178 default:
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);
185 net_mask_count++;
186 continue;
188 #ifdef HAS_IPV6
189 else if (SOCK_ADDR_FAMILY(sa) == AF_INET6) {
190 MAI_HOSTADDR_STR hostaddr;
191 unsigned char *ac;
192 unsigned char *end;
193 unsigned char ch;
194 struct sockaddr_in6 net6;
196 switch (mask_style) {
199 * There are no classes for IPv6. We default to subnets
200 * instead.
202 case MASK_STYLE_CLASS:
204 /* FALLTHROUGH */
207 * Subnet mask.
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;
213 while (ac < end) {
214 if ((ch = *ac++) == (unsigned char) -1) {
215 shift -= CHAR_BIT;
216 continue;
217 } else {
218 while (ch != 0)
219 shift--, ch <<= 1;
220 break;
223 break;
226 * Host only. Do not relay authorize other hosts.
228 case MASK_STYLE_HOST:
229 shift = 0;
230 break;
232 default:
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);
245 net_mask_count++;
246 continue;
248 #endif
249 else {
250 msg_warn("%s: skipping unknown address family %d",
251 myname, SOCK_ADDR_FAMILY(sa));
252 continue;
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);
271 argv_free(argv);
272 been_here_free(dup_filter);
274 if (msg_verbose)
275 msg_info("%s: %s", myname, vstring_str(result));
277 return (vstring_str(result));
280 #ifdef TEST
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;
290 if (argc != 4)
291 msg_fatal("usage: %s protocols mask_style interface_list (e.g. \"all subnet all\")",
292 argv[0]);
293 msg_verbose = 10;
294 proto_info = inet_proto_init(argv[0], argv[1]);
295 var_mynetworks_style = argv[2];
296 var_inet_interfaces = argv[3];
297 mynetworks();
298 return (0);
301 #endif