Postfix3.3.1
mynetworks.c
[詳解]
1 /*++
2 /* NAME
3 /* mynetworks 3
4 /* SUMMARY
5 /* generate patterns for my own interface addresses
6 /* SYNOPSIS
7 /* #include <mynetworks.h>
8 /*
9 /* const char *mynetworks()
10 /* AUXILIARY FUNCTIONS
11 /* const char *mynetworks_host()
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.
16 /*
17 /* The interface list is specified with the "inet_interfaces"
18 /* configuration parameter.
19 /*
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 /*
25 /* mynetworks_host() uses the "host" style.
26 /* LICENSE
27 /* .ad
28 /* .fi
29 /* The Secure Mailer license must be distributed with this software.
30 /* AUTHOR(S)
31 /* Wietse Venema
32 /* IBM T.J. Watson Research
33 /* P.O. Box 704
34 /* Yorktown Heights, NY 10598, USA
35 /*
36 /* Dean C. Strik
37 /* Department ICT Services
38 /* Eindhoven University of Technology
39 /* P.O. Box 513
40 /* 5600 MB Eindhoven, Netherlands
41 /* E-mail: <dean@ipnet6.org>
42 /*--*/
43 
44 /* System library. */
45 
46 #include <sys_defs.h>
47 #include <sys/param.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 
51 #ifndef IN_CLASSD_NET
52 #define IN_CLASSD_NET 0xf0000000
53 #define IN_CLASSD_NSHIFT 28
54 #endif
55 
56 /* Utility library. */
57 
58 #include <msg.h>
59 #include <vstring.h>
60 #include <inet_addr_list.h>
61 #include <name_mask.h>
62 #include <myaddrinfo.h>
63 #include <mask_addr.h>
64 #include <argv.h>
65 #include <inet_proto.h>
66 #include <mymalloc.h>
67 
68 /* Global library. */
69 
70 #include <own_inet_addr.h>
71 #include <mail_params.h>
72 #include <mynetworks.h>
73 #include <sock_addr.h>
74 #include <been_here.h>
75 
76 /* Application-specific. */
77 
78 #define MASK_STYLE_CLASS (1 << 0)
79 #define MASK_STYLE_SUBNET (1 << 1)
80 #define MASK_STYLE_HOST (1 << 2)
81 
82 static const NAME_MASK mask_styles[] = {
86  0,
87 };
88 
89 /* mynetworks_core - return patterns for specific mynetworks style */
90 
91 static const char *mynetworks_core(const char *style)
92 {
93  const char *myname = "mynetworks_core";
94  VSTRING *result;
95  INET_ADDR_LIST *my_addr_list;
96  INET_ADDR_LIST *my_mask_list;
97  unsigned shift;
98  unsigned junk;
99  int i;
100  unsigned mask_style;
101  struct sockaddr_storage *sa;
102  struct sockaddr_storage *ma;
103  int net_mask_count = 0;
104  ARGV *argv;
105  BH_TABLE *dup_filter;
106  char **cpp;
107 
108  /*
109  * Avoid run-time errors when all network protocols are disabled. We
110  * can't look up interface information, and we can't convert explicit
111  * names or addresses.
112  */
113  if (inet_proto_info()->ai_family_list[0] == 0) {
114  if (msg_verbose)
115  msg_info("skipping %s setting - "
116  "all network protocols are disabled",
118  return (mystrdup(""));
119  }
120  mask_style = name_mask("mynetworks mask style", mask_styles, style);
121 
122  /*
123  * XXX Workaround: name_mask() needs a flags argument so that we can
124  * require exactly one value, or we need to provide an API that is
125  * dedicated for single-valued flags.
126  *
127  * XXX Why not use name_code() instead?
128  */
129  for (i = 0, junk = mask_style; junk != 0; junk >>= 1U)
130  i += (junk & 1);
131  if (i != 1)
132  msg_fatal("bad %s value: %s; specify exactly one value",
134 
135  result = vstring_alloc(20);
136  my_addr_list = own_inet_addr_list();
137  my_mask_list = own_inet_mask_list();
138 
139  for (sa = my_addr_list->addrs, ma = my_mask_list->addrs;
140  sa < my_addr_list->addrs + my_addr_list->used;
141  sa++, ma++) {
142  unsigned long addr;
143  unsigned long mask;
144  struct in_addr net;
145 
146  if (SOCK_ADDR_FAMILY(sa) == AF_INET) {
147  addr = ntohl(SOCK_ADDR_IN_ADDR(sa).s_addr);
148  mask = ntohl(SOCK_ADDR_IN_ADDR(ma).s_addr);
149 
150  switch (mask_style) {
151 
152  /*
153  * Natural mask. This is dangerous if you're customer of an
154  * ISP who gave you a small portion of their network.
155  */
156  case MASK_STYLE_CLASS:
157  if (IN_CLASSA(addr)) {
158  mask = IN_CLASSA_NET;
159  shift = IN_CLASSA_NSHIFT;
160  } else if (IN_CLASSB(addr)) {
161  mask = IN_CLASSB_NET;
162  shift = IN_CLASSB_NSHIFT;
163  } else if (IN_CLASSC(addr)) {
164  mask = IN_CLASSC_NET;
165  shift = IN_CLASSC_NSHIFT;
166  } else if (IN_CLASSD(addr)) {
167  mask = IN_CLASSD_NET;
168  shift = IN_CLASSD_NSHIFT;
169  } else {
170  msg_fatal("%s: unknown address class: %s",
171  myname, inet_ntoa(SOCK_ADDR_IN_ADDR(sa)));
172  }
173  break;
174 
175  /*
176  * Subnet mask. This is less unsafe, but still bad if you're
177  * connected to a large subnet.
178  */
179  case MASK_STYLE_SUBNET:
180  for (junk = mask, shift = MAI_V4ADDR_BITS; junk != 0;
181  shift--, junk <<= 1)
182  /* void */ ;
183  break;
184 
185  /*
186  * Host only. Do not relay authorize other hosts.
187  */
188  case MASK_STYLE_HOST:
189  mask = ~0UL;
190  shift = 0;
191  break;
192 
193  default:
194  msg_panic("unknown mynetworks mask style: %s",
196  }
197  net.s_addr = htonl(addr & mask);
198  vstring_sprintf_append(result, "%s/%d ",
199  inet_ntoa(net), MAI_V4ADDR_BITS - shift);
200  net_mask_count++;
201  continue;
202  }
203 #ifdef HAS_IPV6
204  else if (SOCK_ADDR_FAMILY(sa) == AF_INET6) {
205  MAI_HOSTADDR_STR hostaddr;
206  unsigned char *ac;
207  unsigned char *end;
208  unsigned char ch;
209  struct sockaddr_in6 net6;
210 
211  switch (mask_style) {
212 
213  /*
214  * There are no classes for IPv6. We default to subnets
215  * instead.
216  */
217  case MASK_STYLE_CLASS:
218 
219  /* FALLTHROUGH */
220 
221  /*
222  * Subnet mask.
223  */
224  case MASK_STYLE_SUBNET:
225  ac = (unsigned char *) &SOCK_ADDR_IN6_ADDR(ma);
226  end = ac + sizeof(SOCK_ADDR_IN6_ADDR(ma));
227  shift = MAI_V6ADDR_BITS;
228  while (ac < end) {
229  if ((ch = *ac++) == (unsigned char) ~0U) {
230  shift -= CHAR_BIT;
231  continue;
232  } else {
233  while (ch != 0)
234  shift--, ch <<= 1;
235  break;
236  }
237  }
238  break;
239 
240  /*
241  * Host only. Do not relay authorize other hosts.
242  */
243  case MASK_STYLE_HOST:
244  shift = 0;
245  break;
246 
247  default:
248  msg_panic("unknown mynetworks mask style: %s",
250  }
251  /* FIX 200501: IPv6 patch did not clear host bits. */
252  net6 = *SOCK_ADDR_IN6_PTR(sa);
253  mask_addr((unsigned char *) &net6.sin6_addr,
254  sizeof(net6.sin6_addr),
255  MAI_V6ADDR_BITS - shift);
257  &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
258  vstring_sprintf_append(result, "[%s]/%d ",
259  hostaddr.buf, MAI_V6ADDR_BITS - shift);
260  net_mask_count++;
261  continue;
262  }
263 #endif
264  else {
265  msg_warn("%s: skipping unknown address family %d",
266  myname, SOCK_ADDR_FAMILY(sa));
267  continue;
268  }
269  }
270 
271  /*
272  * FIX 200501 IPv6 patch produced repeated results. Some systems report
273  * the same interface multiple times, notably multi-homed systems with
274  * IPv6 link-local or site-local addresses. A straight-forward sort+uniq
275  * produces ugly results, though. Instead we preserve the original order
276  * and use a duplicate filter to suppress repeated information.
277  */
278  if (net_mask_count > 1) {
279  argv = argv_split(vstring_str(result), " ");
280  VSTRING_RESET(result);
281  dup_filter = been_here_init(net_mask_count, BH_FLAG_NONE);
282  for (cpp = argv->argv; cpp < argv->argv + argv->argc; cpp++)
283  if (!been_here_fixed(dup_filter, *cpp))
284  vstring_sprintf_append(result, "%s ", *cpp);
285  argv_free(argv);
286  been_here_free(dup_filter);
287  }
288  if (msg_verbose)
289  msg_info("%s: %s", myname, vstring_str(result));
290  return (vstring_export(result));
291 }
292 
293 /* mynetworks - return patterns that match my own networks */
294 
295 const char *mynetworks(void)
296 {
297  static const char *result;
298 
299  if (result == 0)
300  result = mynetworks_core(var_mynetworks_style);
301  return (result);
302 }
303 
304 /* mynetworks_host - return patterns for "host" mynetworks style */
305 
306 const char *mynetworks_host(void)
307 {
308  static const char *result;
309 
310  if (result == 0)
311  result = mynetworks_core(MYNETWORKS_STYLE_HOST);
312  return (result);
313 }
314 
315 #ifdef TEST
316 #include <inet_proto.h>
317 
318 char *var_inet_interfaces;
320 
321 int main(int argc, char **argv)
322 {
323  INET_PROTO_INFO *proto_info;
324 
325  if (argc != 4)
326  msg_fatal("usage: %s protocols mask_style interface_list (e.g. \"all subnet all\")",
327  argv[0]);
328  msg_verbose = 10;
329  proto_info = inet_proto_init(argv[0], argv[1]);
330  var_mynetworks_style = argv[2];
331  var_inet_interfaces = argv[3];
332  mynetworks();
333  return (0);
334 }
335 
336 #endif
int msg_verbose
Definition: msg.c:177
#define MYNETWORKS_STYLE_SUBNET
Definition: mail_params.h:2045
void mask_addr(unsigned char *addr_bytes, unsigned addr_byte_count, unsigned network_bits)
Definition: mask_addr.c:50
#define BH_FLAG_NONE
Definition: been_here.h:28
char * mystrdup(const char *str)
Definition: mymalloc.c:225
void been_here_free(BH_TABLE *dup_filter)
Definition: been_here.c:116
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define inet_proto_info()
Definition: inet_proto.h:29
int main(int argc, char **argv)
Definition: anvil.c:1010
INET_PROTO_INFO * inet_proto_init(const char *context, const char *protocols)
Definition: inet_proto.c:180
struct sockaddr_storage * addrs
char ** argv
Definition: argv.h:20
#define SOCKADDR_TO_HOSTADDR(sa, salen, host, port, sock)
Definition: myaddrinfo.h:197
BH_TABLE * been_here_init(int limit, int flags)
Definition: been_here.c:103
const char * mynetworks(void)
Definition: mynetworks.c:295
#define IN_CLASSD_NET
Definition: mynetworks.c:52
const char * mynetworks_host(void)
Definition: mynetworks.c:306
#define MAI_V6ADDR_BITS
Definition: myaddrinfo.h:125
char buf[MAI_HOSTADDR_STRSIZE]
Definition: myaddrinfo.h:146
VSTRING * vstring_sprintf_append(VSTRING *vp, const char *format,...)
Definition: vstring.c:624
#define VAR_MYNETWORKS
Definition: mail_params.h:2035
#define MASK_STYLE_HOST
Definition: mynetworks.c:80
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define SOCK_ADDR_PTR(ptr)
Definition: sock_addr.h:24
#define MAI_V4ADDR_BITS
Definition: myaddrinfo.h:124
INET_ADDR_LIST * own_inet_mask_list(void)
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define name_mask(tag, table, str)
Definition: name_mask.h:49
#define IN_CLASSD_NSHIFT
Definition: mynetworks.c:53
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define MASK_STYLE_CLASS
Definition: mynetworks.c:78
ARGV * argv_split(const char *, const char *)
Definition: argv_split.c:63
int been_here_fixed(BH_TABLE *dup_filter, const char *string)
Definition: been_here.c:151
INET_ADDR_LIST * own_inet_addr_list(void)
#define VAR_MYNETWORKS_STYLE
Definition: mail_params.h:2038
#define MYNETWORKS_STYLE_HOST
Definition: mail_params.h:2046
#define SOCK_ADDR_LEN(sa)
Definition: sock_addr.h:78
#define SOCK_ADDR_FAMILY(ptr)
Definition: sock_addr.h:25
#define MASK_STYLE_SUBNET
Definition: mynetworks.c:79
ssize_t argc
Definition: argv.h:19
#define MYNETWORKS_STYLE_CLASS
Definition: mail_params.h:2044
#define SOCK_ADDR_IN_ADDR(sa)
Definition: sock_addr.h:33
char * var_inet_interfaces
Definition: mail_params.c:258
char * var_mynetworks_style
Definition: mail_params.c:288
char * vstring_export(VSTRING *vp)
Definition: vstring.c:569
void msg_info(const char *fmt,...)
Definition: msg.c:199