7 /* convert protocol names to assorted constants
9 /* #include <inet_proto.h>
13 /* unsigned ai_family; /* PF_UNSPEC, PF_INET, or PF_INET6 */
14 /* unsigned *ai_family_list; /* PF_INET and/or PF_INET6 */
15 /* unsigned *dns_atype_list;/* TAAAA and/or TA */
16 /* unsigned char *sa_family_list;/* AF_INET6 and/or AF_INET */
20 /* INET_PROTO_INFO *inet_proto_init(context, protocols)
22 /* INET_PROTO_INFO *inet_proto_info()
24 /* inet_proto_init() converts a string with protocol names
25 /* into null-terminated lists of appropriate constants used
26 /* by Postfix library routines. The idea is that one should
27 /* be able to configure an MTA for IPv4 only, without having
28 /* to recompile code (what a concept).
30 /* Unfortunately, some compilers won't link initialized data
31 /* without a function call into the same source module, so
32 /* we invoke inet_proto_info() in order to access the result
33 /* from inet_proto_init() from within library routines.
34 /* inet_proto_info() also conveniently initializes the data
35 /* to built-in defaults.
39 /* Typically, a configuration parameter name.
41 /* Null-terminated string with protocol names separated by
42 /* whitespace and/or commas:
44 /* .IP INET_PROTO_NAME_ALL
45 /* Enable all available IP protocols.
46 /* .IP INET_PROTO_NAME_IPV4
47 /* Enable IP version 4 support.
48 /* .IP INET_PROTO_NAME_IPV6
49 /* Enable IP version 6 support.
54 /* Only one of PF_UNSPEC, PF_INET, or PF_INET6. This can be
55 /* used as input for the getaddrinfo() and getnameinfo()
58 /* One or more of PF_INET or PF_INET6. This can be used as
59 /* input for the inet_addr_local() routine.
61 /* One or more of T_AAAA or TA. This can be used as input for
62 /* the dns_lookup_v() and dns_lookup_l() routines.
64 /* One or more of AF_INET6 or AF_INET. This can be used as an
65 /* output filter for the results from the getaddrinfo() and
66 /* getnameinfo() routines.
68 /* msg(3) diagnostics interface
70 /* This module will report if IPv6 is unavailable, and will
71 /* disable IPv6 support in Postfix. When IPv6 is the only
72 /* selected protocol, this is a fatal error.
74 /* Fatal errors: memory allocation problem.
78 /* The Secure Mailer license must be distributed with this software.
81 /* IBM T.J. Watson Research
83 /* Yorktown Heights, NY 10598, USA
89 #include <netinet/in.h>
90 #include <arpa/nameser.h>
91 #ifdef RESOLVE_H_NEEDS_STDIO_H
98 /* Utility library. */
100 #include <mymalloc.h>
102 #include <myaddrinfo.h>
103 #include <name_mask.h>
104 #include <inet_proto.h>
107 * Application-specific.
111 * Run-time initialization, so we can work around LINUX where IPv6 falls
112 * flat on its face because it is not turned on in the kernel.
114 INET_PROTO_INFO
*inet_proto_table
= 0;
117 * Infrastructure: lookup table with the protocol names that we support.
119 #define INET_PROTO_MASK_IPV4 (1<<0)
120 #define INET_PROTO_MASK_IPV6 (1<<1)
122 static const NAME_MASK proto_table
[] = {
124 INET_PROTO_NAME_ALL
, INET_PROTO_MASK_IPV4
| INET_PROTO_MASK_IPV6
,
125 INET_PROTO_NAME_IPV6
, INET_PROTO_MASK_IPV6
,
127 INET_PROTO_NAME_ALL
, INET_PROTO_MASK_IPV4
,
129 INET_PROTO_NAME_IPV4
, INET_PROTO_MASK_IPV4
,
133 /* make_uchar_vector - create and initialize uchar vector */
135 static unsigned char *make_uchar_vector(int len
,...)
137 const char *myname
= "make_uchar_vector";
144 msg_panic("%s: bad vector length: %d", myname
, len
);
145 vp
= (unsigned char *) mymalloc(sizeof(*vp
) * len
);
146 for (count
= 0; count
< len
; count
++)
147 vp
[count
] = va_arg(ap
, unsigned);
152 /* make_unsigned_vector - create and initialize integer vector */
154 static unsigned *make_unsigned_vector(int len
,...)
156 const char *myname
= "make_unsigned_vector";
163 msg_panic("%s: bad vector length: %d", myname
, len
);
164 vp
= (unsigned *) mymalloc(sizeof(*vp
) * len
);
165 for (count
= 0; count
< len
; count
++)
166 vp
[count
] = va_arg(ap
, unsigned);
171 /* inet_proto_free - destroy data */
173 static void inet_proto_free(INET_PROTO_INFO
*pf
)
175 myfree((char *) pf
->ai_family_list
);
176 myfree((char *) pf
->dns_atype_list
);
177 myfree((char *) pf
->sa_family_list
);
181 /* inet_proto_init - convert protocol names to library inputs */
183 INET_PROTO_INFO
*inet_proto_init(const char *context
, const char *protocols
)
185 const char *myname
= "inet_proto";
191 * Store addess family etc. info as null-terminated vectors. If that
192 * breaks because we must be able to store nulls, we'll deal with the
193 * additional complexity.
195 * XXX Use compile-time initialized data templates instead of building the
198 inet_proto_mask
= name_mask(context
, proto_table
, protocols
);
199 switch (inet_proto_mask
) {
201 case INET_PROTO_MASK_IPV6
:
202 if ((sock
= socket(PF_INET6
, SOCK_STREAM
, 0)) >= 0) {
204 pf
= (INET_PROTO_INFO
*) mymalloc(sizeof(*pf
));
205 pf
->ai_family
= PF_INET6
;
206 pf
->ai_family_list
= make_unsigned_vector(2, PF_INET6
, 0);
207 pf
->dns_atype_list
= make_unsigned_vector(2, T_AAAA
, 0);
208 pf
->sa_family_list
= make_uchar_vector(2, AF_INET6
, 0);
210 } else if (errno
== EAFNOSUPPORT
) {
211 msg_fatal("%s: IPv6 support is disabled: %m", context
);
213 msg_fatal("socket: %m");
215 case (INET_PROTO_MASK_IPV6
| INET_PROTO_MASK_IPV4
):
216 if ((sock
= socket(PF_INET6
, SOCK_STREAM
, 0)) >= 0) {
218 pf
= (INET_PROTO_INFO
*) mymalloc(sizeof(*pf
));
219 pf
->ai_family
= PF_UNSPEC
;
220 pf
->ai_family_list
= make_unsigned_vector(3, PF_INET
, PF_INET6
, 0);
221 pf
->dns_atype_list
= make_unsigned_vector(3, T_A
, T_AAAA
, 0);
222 pf
->sa_family_list
= make_uchar_vector(3, AF_INET
, AF_INET6
, 0);
224 } else if (errno
== EAFNOSUPPORT
) {
225 msg_warn("%s: IPv6 support is disabled: %m", context
);
226 msg_warn("%s: configuring for IPv4 support only", context
);
229 msg_fatal("socket: %m");
232 case INET_PROTO_MASK_IPV4
:
233 pf
= (INET_PROTO_INFO
*) mymalloc(sizeof(*pf
));
234 pf
->ai_family
= PF_INET
;
235 pf
->ai_family_list
= make_unsigned_vector(2, PF_INET
, 0);
236 pf
->dns_atype_list
= make_unsigned_vector(2, T_A
, 0);
237 pf
->sa_family_list
= make_uchar_vector(2, AF_INET
, 0);
240 msg_panic("%s: bad inet_proto_mask 0x%x", myname
, inet_proto_mask
);
242 if (inet_proto_table
)
243 inet_proto_free(inet_proto_table
);
244 return (inet_proto_table
= pf
);
250 * Small driver for unit tests.
252 int main(int argc
, char **argv
)
254 const char *myname
= argv
[0];
258 msg_fatal("usage: %s protocol(s)...", myname
);
261 msg_info("=== %s ===", *argv
);
263 inet_proto_init(myname
, *argv
);
264 pf
= inet_proto_table
;
265 msg_info("ai_family = %u", pf
->ai_family
);
266 msg_info("ai_family_list = %u %u...",
267 pf
->ai_family_list
[0], pf
->ai_family_list
[1]);
268 msg_info("dns_atype_list = %u %u...",
269 pf
->dns_atype_list
[0], pf
->dns_atype_list
[1]);
270 msg_info("sa_family_list = %u %u...",
271 pf
->sa_family_list
[0], pf
->sa_family_list
[1]);