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) {
93 struct sockaddr_in *sa4;
94 struct sockaddr_in6 *sa6;
96 struct sockaddr_in sa4;
97 static char addr_buf[2][INET6_ADDRSTRLEN];
101 if (u.sa->sa_family == AF_INET6) {
102 if (IN6_IS_ADDR_V4MAPPED(&u.sa6->sin6_addr)) {
103 memset(&sa4, 0, sizeof(sa4));
104 sa4.sin_family = AF_INET;
105 sa4.sin_port = u.sa6->sin6_port;
106 memcpy(&sa4.sin_addr, &u.sa6->sin6_addr.s6_addr[12], 4);
110 if (getnameinfo(u.sa, SOCKADDRP_SIZE(u.sa), addr_buf[i], sizeof(addr_buf[i]),
111 NULL, 0, NI_NUMERICHOST)) {
112 debug(DBG_WARN, "getnameinfo failed");
113 return "getnameinfo_failed";
120 int connectport(int type, char *host, char *port) {
121 struct addrinfo hints, *res0, *res;
124 memset(&hints, 0, sizeof(hints));
125 hints.ai_socktype = type;
126 hints.ai_family = AF_UNSPEC;
128 if (getaddrinfo(host, port, &hints, &res0) != 0) {
129 debug(DBG_ERR, "connectport: can't resolve host %s port %s", host, port);
133 for (res = res0; res; res = res->ai_next) {
134 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
136 debug(DBG_WARN, "connectport: socket failed");
139 if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
141 debug(DBG_WARN, "connectport: connect failed");
150 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
151 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
154 void disable_DF_bit(int socket, struct addrinfo *res) {
155 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
156 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
158 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
161 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
162 action = IP_PMTUDISC_DONT;
163 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
165 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
167 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!");
172 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
174 struct addrinfo *res;
176 for (res = addrinfo; res; res = res->ai_next) {
177 if (family != AF_UNSPEC && family != res->ai_family)
179 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
181 debug(DBG_WARN, "bindtoaddr: socket failed");
185 disable_DF_bit(s,res);
188 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
191 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
193 if (!bind(s, res->ai_addr, res->ai_addrlen))
195 debug(DBG_WARN, "bindtoaddr: bind failed");
201 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
202 int origflags, error = 0, r = -1;
206 origflags = fcntl(s, F_GETFL, 0);
207 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
208 if (!connect(s, addr, addrlen)) {
212 if (errno != EINPROGRESS)
216 FD_SET(s, &writefds);
217 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
221 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
225 fcntl(s, F_SETFL, origflags);
229 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
231 struct addrinfo *res;
236 if (addrinfo && addrinfo->ai_next && timeout > 5)
242 for (res = addrinfo; res; res = res->ai_next) {
243 s = bindtoaddr(src, res->ai_family, 1, 1);
245 debug(DBG_WARN, "connecttoserver: socket failed");
249 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
250 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
252 debug(DBG_WARN, "connecttoserver: connect failed");
259 /* Local Variables: */
260 /* c-file-style: "stroustrup" */