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 <netinet/in.h>
23 #include <sys/select.h>
28 char *stringcopy(const char *s, int len) {
36 debug(DBG_ERR, "stringcopy: malloc failed");
42 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
44 unsigned char *s = (unsigned char *)chars;
46 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
47 for (i = 0; i < len; i++)
48 printf(charfmt ? charfmt : "%c", s[i]);
52 void port_set(struct sockaddr *sa, uint16_t port) {
53 switch (sa->sa_family) {
55 ((struct sockaddr_in *)sa)->sin_port = htons(port);
58 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
63 struct sockaddr *addr_copy(struct sockaddr *in) {
64 struct sockaddr *out = NULL;
66 switch (in->sa_family) {
68 out = malloc(sizeof(struct sockaddr_in));
70 memset(out, 0, sizeof(struct sockaddr_in));
71 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
75 out = malloc(sizeof(struct sockaddr_in6));
77 memset(out, 0, sizeof(struct sockaddr_in6));
78 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
82 out->sa_family = in->sa_family;
84 out->sa_len = in->sa_len;
89 char *addr2string(struct sockaddr *addr) {
90 struct sockaddr_in6 *sa6;
91 struct sockaddr_in sa4;
92 static char addr_buf[2][INET6_ADDRSTRLEN];
95 if (addr->sa_family == AF_INET6) {
96 sa6 = (struct sockaddr_in6 *)addr;
97 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
98 memset(&sa4, 0, sizeof(sa4));
99 sa4.sin_family = AF_INET;
100 sa4.sin_port = sa6->sin6_port;
101 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
102 addr = (struct sockaddr *)&sa4;
105 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
106 NULL, 0, NI_NUMERICHOST)) {
107 debug(DBG_WARN, "getnameinfo failed");
108 return "getnameinfo_failed";
115 int connectport(int type, char *host, char *port) {
116 struct addrinfo hints, *res0, *res;
119 memset(&hints, 0, sizeof(hints));
120 hints.ai_socktype = type;
121 hints.ai_family = AF_UNSPEC;
123 if (getaddrinfo(host, port, &hints, &res0) != 0) {
124 debug(DBG_ERR, "connectport: can't resolve host %s port %s", host, port);
128 for (res = res0; res; res = res->ai_next) {
129 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
131 debug(DBG_WARN, "connectport: socket failed");
134 if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
136 debug(DBG_WARN, "connectport: connect failed");
145 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
146 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
149 void disable_DF_bit(int socket, struct addrinfo *res) {
150 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
151 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
153 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
156 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
157 action = IP_PMTUDISC_DONT;
158 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
160 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
162 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!");
167 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
169 struct addrinfo *res;
171 for (res = addrinfo; res; res = res->ai_next) {
172 if (family != AF_UNSPEC && family != res->ai_family)
174 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
176 debug(DBG_WARN, "bindtoaddr: socket failed");
180 disable_DF_bit(s,res);
183 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
186 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
188 if (!bind(s, res->ai_addr, res->ai_addrlen))
190 debug(DBG_WARN, "bindtoaddr: bind failed");
196 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
197 int origflags, error = 0, r = -1;
201 origflags = fcntl(s, F_GETFL, 0);
202 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
203 if (!connect(s, addr, addrlen)) {
207 if (errno != EINPROGRESS)
211 FD_SET(s, &writefds);
212 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
216 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
220 fcntl(s, F_SETFL, origflags);
224 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
226 struct addrinfo *res;
231 if (addrinfo && addrinfo->ai_next && timeout > 5)
237 for (res = addrinfo; res; res = res->ai_next) {
238 s = bindtoaddr(src, res->ai_family, 1, 1);
240 debug(DBG_WARN, "connecttoserver: socket failed");
244 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
245 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
247 debug(DBG_WARN, "connecttoserver: connect failed");
254 /* Local Variables: */
255 /* c-file-style: "stroustrup" */