1 /* Copyright (c) 2006-2010, UNINETT AS
2 * Copyright (c) 2010-2012, NORDUnet A/S */
3 /* See LICENSE for licensing information. */
5 /* Code contributions from:
7 * Stefan Winter <stefan.winter@restena.lu>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
19 #include <sys/select.h>
24 char *stringcopy(const char *s, int len) {
32 debug(DBG_ERR, "stringcopy: malloc failed");
38 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
40 unsigned char *s = (unsigned char *)chars;
42 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
43 for (i = 0; i < len; i++)
44 printf(charfmt ? charfmt : "%c", s[i]);
48 void port_set(struct sockaddr *sa, uint16_t port) {
49 switch (sa->sa_family) {
51 ((struct sockaddr_in *)sa)->sin_port = htons(port);
54 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
59 struct sockaddr *addr_copy(struct sockaddr *in) {
60 struct sockaddr *out = NULL;
62 switch (in->sa_family) {
64 out = malloc(sizeof(struct sockaddr_in));
66 memset(out, 0, sizeof(struct sockaddr_in));
67 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
71 out = malloc(sizeof(struct sockaddr_in6));
73 memset(out, 0, sizeof(struct sockaddr_in6));
74 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
78 out->sa_family = in->sa_family;
80 out->sa_len = in->sa_len;
85 char *addr2string(struct sockaddr *addr) {
86 struct sockaddr_in6 *sa6;
87 struct sockaddr_in sa4;
88 static char addr_buf[2][INET6_ADDRSTRLEN];
91 if (addr->sa_family == AF_INET6) {
92 sa6 = (struct sockaddr_in6 *)addr;
93 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
94 memset(&sa4, 0, sizeof(sa4));
95 sa4.sin_family = AF_INET;
96 sa4.sin_port = sa6->sin6_port;
97 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
98 addr = (struct sockaddr *)&sa4;
101 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
102 NULL, 0, NI_NUMERICHOST)) {
103 debug(DBG_WARN, "getnameinfo failed");
104 return "getnameinfo_failed";
109 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
110 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
113 void disable_DF_bit(int socket, struct addrinfo *res) {
114 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
115 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
117 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
120 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
121 action = IP_PMTUDISC_DONT;
122 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
124 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
126 debug(DBG_INFO, "Non-Linux platform, unable to unset DF bit for UDP. You should check with tcpdump whether radsecproxy will send its UDP packets with DF bit set!");
131 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
133 struct addrinfo *res;
135 for (res = addrinfo; res; res = res->ai_next) {
136 if (family != AF_UNSPEC && family != res->ai_family)
138 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
140 debug(DBG_WARN, "bindtoaddr: socket failed");
144 disable_DF_bit(s,res);
147 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
150 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
152 if (!bind(s, res->ai_addr, res->ai_addrlen))
154 debug(DBG_WARN, "bindtoaddr: bind failed");
160 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
161 int origflags, error = 0, r = -1;
165 origflags = fcntl(s, F_GETFL, 0);
166 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
167 if (!connect(s, addr, addrlen)) {
171 if (errno != EINPROGRESS)
175 FD_SET(s, &writefds);
176 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
180 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
184 fcntl(s, F_SETFL, origflags);
188 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
190 struct addrinfo *res;
195 if (addrinfo && addrinfo->ai_next && timeout > 5)
201 for (res = addrinfo; res; res = res->ai_next) {
202 s = bindtoaddr(src, res->ai_family, 1, 1);
204 debug(DBG_WARN, "connecttoserver: socket failed");
208 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
209 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
211 debug(DBG_WARN, "connecttoserver: connect failed");
218 /* Local Variables: */
219 /* c-file-style: "stroustrup" */