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";
113 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
114 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
117 void disable_DF_bit(int socket, struct addrinfo *res) {
118 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
119 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
121 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
124 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
125 action = IP_PMTUDISC_DONT;
126 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
128 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
130 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!");
135 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
137 struct addrinfo *res;
139 for (res = addrinfo; res; res = res->ai_next) {
140 if (family != AF_UNSPEC && family != res->ai_family)
142 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
144 debug(DBG_WARN, "bindtoaddr: socket failed");
148 disable_DF_bit(s,res);
151 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
154 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
156 if (!bind(s, res->ai_addr, res->ai_addrlen))
158 debug(DBG_WARN, "bindtoaddr: bind failed");
164 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
165 int origflags, error = 0, r = -1;
169 origflags = fcntl(s, F_GETFL, 0);
170 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
171 if (!connect(s, addr, addrlen)) {
175 if (errno != EINPROGRESS)
179 FD_SET(s, &writefds);
180 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
184 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
188 fcntl(s, F_SETFL, origflags);
192 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
194 struct addrinfo *res;
199 if (addrinfo && addrinfo->ai_next && timeout > 5)
205 for (res = addrinfo; res; res = res->ai_next) {
206 s = bindtoaddr(src, res->ai_family, 1, 1);
208 debug(DBG_WARN, "connecttoserver: socket failed");
212 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
213 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
215 debug(DBG_WARN, "connecttoserver: connect failed");
222 /* Local Variables: */
223 /* c-file-style: "stroustrup" */