summaryrefslogtreecommitdiffstats
path: root/src/util/myaddrinfo.h
blob: 94f1e9fa68fe79b82cb510a77200563f67efc569 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#ifndef _MYADDRINFO_H_INCLUDED_
#define _MYADDRINFO_H_INCLUDED_

/*++
/* NAME
/*	myaddrinfo 3h
/* SUMMARY
/*	addrinfo encapsulation and emulation
/* SYNOPSIS
/*	#include <myaddrinfo.h>
/* DESCRIPTION
/* .nf

 /*
  * System library.
  */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>			/* MAI_STRERROR() */
#include <limits.h>			/* CHAR_BIT */

 /*
  * Backwards compatibility support for IPV4 systems without addrinfo API.
  */
#ifdef EMULATE_IPV4_ADDRINFO

 /*
  * Avoid clashes with global symbols, just in case some third-party library
  * provides its own addrinfo() implementation. This also allows us to test
  * the IPV4 emulation code on an IPV6 enabled system.
  */
#undef  freeaddrinfo
#define freeaddrinfo	mai_freeaddrinfo
#undef  gai_strerror
#define gai_strerror	mai_strerror
#undef  addrinfo
#define addrinfo	mai_addrinfo
#undef  sockaddr_storage
#define sockaddr_storage mai_sockaddr_storage

 /*
  * Modern systems define this in <netdb.h>.
  */
struct addrinfo {
    int     ai_flags;			/* AI_PASSIVE|CANONNAME|NUMERICHOST */
    int     ai_family;			/* PF_xxx */
    int     ai_socktype;		/* SOCK_xxx */
    int     ai_protocol;		/* 0 or IPPROTO_xxx */
    size_t  ai_addrlen;			/* length of ai_addr */
    char   *ai_canonname;		/* canonical name for nodename */
    struct sockaddr *ai_addr;		/* binary address */
    struct addrinfo *ai_next;		/* next structure in linked list */
};

 /*
  * Modern systems define this in <sys/socket.h>.
  */
struct sockaddr_storage {
    struct sockaddr_in dummy;		/* alignment!! */
};

 /*
  * Result codes. See gai_strerror() for text. Undefine already imported
  * definitions so that we can test the IPv4-only emulation on a modern
  * system without getting a ton of compiler warnings.
  */
#undef  EAI_ADDRFAMILY
#define EAI_ADDRFAMILY   1
#undef  EAI_AGAIN
#define EAI_AGAIN        2
#undef  EAI_BADFLAGS
#define EAI_BADFLAGS     3
#undef  EAI_FAIL
#define EAI_FAIL         4
#undef  EAI_FAMILY
#define EAI_FAMILY       5
#undef  EAI_MEMORY
#define EAI_MEMORY       6
#undef  EAI_NODATA
#define EAI_NODATA       7
#undef  EAI_NONAME
#define EAI_NONAME       8
#undef  EAI_SERVICE
#define EAI_SERVICE      9
#undef  EAI_SOCKTYPE
#define EAI_SOCKTYPE    10
#undef  EAI_SYSTEM
#define EAI_SYSTEM      11
#undef  EAI_BADHINTS
#define EAI_BADHINTS    12
#undef  EAI_PROTOCOL
#define EAI_PROTOCOL    13
#undef  EAI_RESNULL
#define EAI_RESNULL     14
#undef  EAI_MAX
#define EAI_MAX         15

extern void freeaddrinfo(struct addrinfo *);
extern char *gai_strerror(int);

#endif

 /*
  * Bounds grow in leaps. These macros attempt to keep non-library code free
  * from IPV6 #ifdef pollution. Avoid macro names that end in STRLEN because
  * they suggest that space for the null terminator is not included.
  */
#ifdef HAS_IPV6
# define MAI_HOSTADDR_STRSIZE	INET6_ADDRSTRLEN
#else
# ifndef INET_ADDRSTRLEN
#  define INET_ADDRSTRLEN	16
# endif
# define MAI_HOSTADDR_STRSIZE	INET_ADDRSTRLEN
#endif

#define MAI_HOSTNAME_STRSIZE	1025
#define MAI_SERVNAME_STRSIZE	32
#define MAI_SERVPORT_STRSIZE	sizeof("65535")

#define MAI_V4ADDR_BITS		32
#define MAI_V6ADDR_BITS		128
#define MAI_V4ADDR_BYTES	((MAI_V4ADDR_BITS + (CHAR_BIT - 1))/CHAR_BIT)
#define MAI_V6ADDR_BYTES	((MAI_V6ADDR_BITS + (CHAR_BIT - 1))/CHAR_BIT)

 /*
  * Routines and data structures to hide some of the complexity of the
  * addrinfo API. They still don't hide that we may get results for address
  * families that we aren't interested in.
  * 
  * Note: the getnameinfo() and inet_ntop() system library functions use unsafe
  * APIs with separate pointer and length arguments. To avoid buffer overflow
  * problems with these functions, Postfix uses pointers to structures
  * internally. This way the compiler can enforce that callers provide
  * buffers with the appropriate length, instead of having to trust that
  * callers will never mess up some length calculation.
  */
typedef struct {
    char    buf[MAI_HOSTNAME_STRSIZE];
} MAI_HOSTNAME_STR;

typedef struct {
    char    buf[MAI_HOSTADDR_STRSIZE];
} MAI_HOSTADDR_STR;

typedef struct {
    char    buf[MAI_SERVNAME_STRSIZE];
} MAI_SERVNAME_STR;

typedef struct {
    char    buf[MAI_SERVPORT_STRSIZE];
} MAI_SERVPORT_STR;

extern int WARN_UNUSED_RESULT hostname_to_sockaddr_pf(const char *,
			        int, const char *, int, struct addrinfo **);
extern int WARN_UNUSED_RESULT hostaddr_to_sockaddr(const char *,
			             const char *, int, struct addrinfo **);
extern int WARN_UNUSED_RESULT sockaddr_to_hostaddr(const struct sockaddr *,
	        SOCKADDR_SIZE, MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *, int);
extern int WARN_UNUSED_RESULT sockaddr_to_hostname(const struct sockaddr *,
	        SOCKADDR_SIZE, MAI_HOSTNAME_STR *, MAI_SERVNAME_STR *, int);
extern void myaddrinfo_control(int,...);

#define MAI_CTL_END	0		/* list terminator */

#define MAI_STRERROR(e) ((e) == EAI_SYSTEM ? strerror(errno) : gai_strerror(e))

#define hostname_to_sockaddr(host, serv, sock, res) \
	hostname_to_sockaddr_pf((host), PF_UNSPEC, (serv), (sock), (res))

 /*
  * Macros for the case where we really don't want to be bothered with things
  * that may fail.
  */
#define HOSTNAME_TO_SOCKADDR_PF(host, pf, serv, sock, res) \
    do { \
	int _aierr; \
	_aierr = hostname_to_sockaddr_pf((host), (pf), (serv), (sock), (res)); \
	if (_aierr) \
	    msg_fatal("hostname_to_sockaddr_pf: %s", MAI_STRERROR(_aierr)); \
    } while (0)

#define HOSTNAME_TO_SOCKADDR(host, serv, sock, res) \
	HOSTNAME_TO_SOCKADDR_PF((host), PF_UNSPEC, (serv), (sock), (res))

#define HOSTADDR_TO_SOCKADDR(host, serv, sock, res) \
    do { \
	int _aierr; \
	_aierr = hostaddr_to_sockaddr((host), (serv), (sock), (res)); \
	if (_aierr) \
	    msg_fatal("hostaddr_to_sockaddr: %s", MAI_STRERROR(_aierr)); \
    } while (0)

#define SOCKADDR_TO_HOSTADDR(sa, salen, host, port, sock) \
    do { \
	int _aierr; \
	_aierr = sockaddr_to_hostaddr((sa), (salen), (host), (port), (sock)); \
	if (_aierr) \
	    msg_fatal("sockaddr_to_hostaddr: %s", MAI_STRERROR(_aierr)); \
    } while (0)

#define SOCKADDR_TO_HOSTNAME(sa, salen, host, service, sock) \
    do { \
	int _aierr; \
	_aierr = sockaddr_to_hostname((sa), (salen), (host), (service), (sock)); \
	if (_aierr) \
	    msg_fatal("sockaddr_to_hostname: %s", MAI_STRERROR(_aierr)); \
    } while (0)

/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*--*/

#endif