1 /* Copyright (c) 2006-2009, Stig Venaas, UNINETT AS.
2 * Copyright (c) 2010, UNINETT AS, NORDUnet A/S.
3 * Copyright (c) 2010-2012, NORDUnet A/S. */
4 /* See LICENSE for licensing information. */
6 /* Code contributions from:
8 * Stefan Winter <stefan.winter@restena.lu>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
20 #include <sys/select.h>
25 char *stringcopy(const char *s, int len) {
33 debug(DBG_ERR, "stringcopy: malloc failed");
39 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
41 unsigned char *s = (unsigned char *)chars;
43 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
44 for (i = 0; i < len; i++)
45 printf(charfmt ? charfmt : "%c", s[i]);
49 void port_set(struct sockaddr *sa, uint16_t port) {
50 switch (sa->sa_family) {
52 ((struct sockaddr_in *)sa)->sin_port = htons(port);
55 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
60 struct sockaddr *addr_copy(struct sockaddr *in) {
61 struct sockaddr *out = NULL;
63 switch (in->sa_family) {
65 out = malloc(sizeof(struct sockaddr_in));
67 memset(out, 0, sizeof(struct sockaddr_in));
68 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
72 out = malloc(sizeof(struct sockaddr_in6));
74 memset(out, 0, sizeof(struct sockaddr_in6));
75 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
79 out->sa_family = in->sa_family;
81 out->sa_len = in->sa_len;
86 char *addr2string(struct sockaddr *addr) {
87 struct sockaddr_in6 *sa6;
88 struct sockaddr_in sa4;
89 static char addr_buf[2][INET6_ADDRSTRLEN];
92 if (addr->sa_family == AF_INET6) {
93 sa6 = (struct sockaddr_in6 *)addr;
94 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
95 memset(&sa4, 0, sizeof(sa4));
96 sa4.sin_family = AF_INET;
97 sa4.sin_port = sa6->sin6_port;
98 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
99 addr = (struct sockaddr *)&sa4;
102 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
103 NULL, 0, NI_NUMERICHOST)) {
104 debug(DBG_WARN, "getnameinfo failed");
105 return "getnameinfo_failed";
110 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
111 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
114 void disable_DF_bit(int socket, struct addrinfo *res) {
115 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
116 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
118 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
121 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
122 action = IP_PMTUDISC_DONT;
123 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
125 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
127 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!");
132 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
134 struct addrinfo *res;
136 for (res = addrinfo; res; res = res->ai_next) {
137 if (family != AF_UNSPEC && family != res->ai_family)
139 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
141 debug(DBG_WARN, "bindtoaddr: socket failed");
145 disable_DF_bit(s,res);
148 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
151 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
153 if (!bind(s, res->ai_addr, res->ai_addrlen))
155 debug(DBG_WARN, "bindtoaddr: bind failed");
161 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
162 int origflags, error = 0, r = -1;
166 origflags = fcntl(s, F_GETFL, 0);
167 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
168 if (!connect(s, addr, addrlen)) {
172 if (errno != EINPROGRESS)
176 FD_SET(s, &writefds);
177 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
181 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
185 fcntl(s, F_SETFL, origflags);
189 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
191 struct addrinfo *res;
196 if (addrinfo && addrinfo->ai_next && timeout > 5)
202 for (res = addrinfo; res; res = res->ai_next) {
203 s = bindtoaddr(src, res->ai_family, 1, 1);
205 debug(DBG_WARN, "connecttoserver: socket failed");
209 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
210 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
212 debug(DBG_WARN, "connecttoserver: connect failed");
219 /* Local Variables: */
220 /* c-file-style: "stroustrup" */