2 * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
9 /* Code contributions from:
11 * Stefan Winter <stefan.winter@restena.lu>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <netinet/in.h>
24 #include <sys/select.h>
26 #include "rsp_debug.h"
29 char *stringcopy(const char *s, int len) {
37 debug(DBG_ERR, "stringcopy: malloc failed");
43 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
45 unsigned char *s = (unsigned char *)chars;
47 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
48 for (i = 0; i < len; i++)
49 printf(charfmt ? charfmt : "%c", s[i]);
53 void port_set(struct sockaddr *sa, uint16_t port) {
54 switch (sa->sa_family) {
56 ((struct sockaddr_in *)sa)->sin_port = htons(port);
59 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
64 struct sockaddr *addr_copy(struct sockaddr *in) {
65 struct sockaddr *out = NULL;
67 switch (in->sa_family) {
69 out = malloc(sizeof(struct sockaddr_in));
71 memset(out, 0, sizeof(struct sockaddr_in));
72 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
76 out = malloc(sizeof(struct sockaddr_in6));
78 memset(out, 0, sizeof(struct sockaddr_in6));
79 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
83 out->sa_family = in->sa_family;
85 out->sa_len = in->sa_len;
90 char *addr2string(struct sockaddr *addr) {
91 struct sockaddr_in6 *sa6;
92 struct sockaddr_in sa4;
93 static char addr_buf[2][INET6_ADDRSTRLEN];
96 if (addr->sa_family == AF_INET6) {
97 sa6 = (struct sockaddr_in6 *)addr;
98 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
99 memset(&sa4, 0, sizeof(sa4));
100 sa4.sin_family = AF_INET;
101 sa4.sin_port = sa6->sin6_port;
102 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
103 addr = (struct sockaddr *)&sa4;
106 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
107 NULL, 0, NI_NUMERICHOST)) {
108 debug(DBG_WARN, "getnameinfo failed");
109 return "getnameinfo_failed";
116 int connectport(int type, char *host, char *port) {
117 struct addrinfo hints, *res0, *res;
120 memset(&hints, 0, sizeof(hints));
121 hints.ai_socktype = type;
122 hints.ai_family = AF_UNSPEC;
124 if (getaddrinfo(host, port, &hints, &res0) != 0) {
125 debug(DBG_ERR, "connectport: can't resolve host %s port %s", host, port);
129 for (res = res0; res; res = res->ai_next) {
130 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
132 debug(DBG_WARN, "connectport: socket failed");
135 if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
137 debug(DBG_WARN, "connectport: connect failed");
146 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
147 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
150 void disable_DF_bit(int socket, struct addrinfo *res) {
151 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
152 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
154 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
157 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
158 action = IP_PMTUDISC_DONT;
159 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
161 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
163 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!");
168 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
170 struct addrinfo *res;
172 for (res = addrinfo; res; res = res->ai_next) {
173 if (family != AF_UNSPEC && family != res->ai_family)
175 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
177 debug(DBG_WARN, "bindtoaddr: socket failed");
181 disable_DF_bit(s,res);
184 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
187 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
189 if (!bind(s, res->ai_addr, res->ai_addrlen))
191 debug(DBG_WARN, "bindtoaddr: bind failed");
197 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
198 int origflags, error = 0, r = -1;
202 origflags = fcntl(s, F_GETFL, 0);
203 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
204 if (!connect(s, addr, addrlen)) {
208 if (errno != EINPROGRESS)
212 FD_SET(s, &writefds);
213 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
217 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
221 fcntl(s, F_SETFL, origflags);
225 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
227 struct addrinfo *res;
232 if (addrinfo && addrinfo->ai_next && timeout > 5)
238 for (res = addrinfo; res; res = res->ai_next) {
239 s = bindtoaddr(src, res->ai_family, 1, 1);
241 debug(DBG_WARN, "connecttoserver: socket failed");
245 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
246 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
248 debug(DBG_WARN, "connecttoserver: connect failed");
255 /* Local Variables: */
256 /* c-file-style: "stroustrup" */