1 /*
2 * lftp - file transfer program
3 *
4 * Copyright (c) 1996-2020 by Alexander V. Lukyanov (lav@yars.free.net)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <netdb.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <netinet/in.h>
28 #ifdef HAVE_NETINET_IN_SYSTM_H
29 # include <netinet/in_systm.h>
30 #endif
31 #ifdef HAVE_NETINET_IP_H
32 # include <netinet/ip.h>
33 #endif
34 #ifdef HAVE_NETINET_TCP_H
35 # include <netinet/tcp.h>
36 #endif
37 #ifdef HAVE_SYS_IOCTL_H
38 # include <sys/ioctl.h>
39 #endif
40 #ifdef HAVE_TERMIOS_H
41 # include <termios.h>
42 #endif
43 #include "SMTask.h"
44 #include "network.h"
45 #include "ResMgr.h"
46 #include "ProtoLog.h"
47 #include "xstring.h"
48
address() const49 const char *sockaddr_u::address() const
50 {
51 #ifdef HAVE_GETNAMEINFO
52 static char buf[NI_MAXHOST];
53 if(getnameinfo(&sa,addr_len(),buf,NI_MAXHOST,0,0,NI_NUMERICHOST)<0)
54 return "????";
55 return buf;
56 #else
57 static char buf[16];
58 if(sa.sa_family!=AF_INET)
59 return "????";
60 unsigned char *a=(unsigned char *)&in.sin_addr;
61 snprintf(buf,16,"%u.%u.%u.%u",a[0],a[1],a[2],a[3]);
62 return buf;
63 #endif
64 }
port() const65 int sockaddr_u::port() const
66 {
67 if(sa.sa_family==AF_INET)
68 return ntohs(in.sin_port);
69 #if INET6
70 if(sa.sa_family==AF_INET6)
71 return ntohs(in6.sin6_port);
72 #endif
73 return 0;
74 }
set_port(int port)75 void sockaddr_u::set_port(int port)
76 {
77 if(sa.sa_family==AF_INET)
78 in.sin_port=htons(port);
79 #if INET6
80 if(sa.sa_family==AF_INET6)
81 in6.sin6_port=htons(port);
82 #endif
83 }
84
to_xstring() const85 const xstring& sockaddr_u::to_xstring() const
86 {
87 return xstring::format("[%s]:%d",address(),port());
88 }
89
is_reserved() const90 bool sockaddr_u::is_reserved() const
91 {
92 if(sa.sa_family==AF_INET)
93 {
94 unsigned char *a=(unsigned char *)&in.sin_addr;
95 return (a[0]==0)
96 || (a[0]==127 && !is_loopback())
97 || (a[0]>=240);
98 }
99 #if INET6
100 if(family()==AF_INET6) {
101 return IN6_IS_ADDR_UNSPECIFIED(&in6.sin6_addr)
102 || IN6_IS_ADDR_V4MAPPED(&in6.sin6_addr)
103 || IN6_IS_ADDR_V4COMPAT(&in6.sin6_addr);
104 }
105 #endif
106 return false;
107 }
108
is_multicast() const109 bool sockaddr_u::is_multicast() const
110 {
111 if(sa.sa_family==AF_INET)
112 {
113 unsigned char *a=(unsigned char *)&in.sin_addr;
114 return (a[0]>=224 && a[0]<240);
115 }
116 #if INET6
117 if(family()==AF_INET6)
118 return IN6_IS_ADDR_MULTICAST(&in6.sin6_addr);
119 #endif
120 return false;
121 }
122
is_private() const123 bool sockaddr_u::is_private() const
124 {
125 if(sa.sa_family==AF_INET)
126 {
127 unsigned char *a=(unsigned char *)&in.sin_addr;
128 return (a[0]==10)
129 || (a[0]==172 && a[1]>=16 && a[1]<32)
130 || (a[0]==192 && a[1]==168)
131 || (a[0]==169 && a[1]==254); // self-assigned
132 }
133 #if INET6
134 if(family()==AF_INET6) {
135 return IN6_IS_ADDR_SITELOCAL(&in6.sin6_addr)
136 || IN6_IS_ADDR_LINKLOCAL(&in6.sin6_addr);
137 }
138 #endif
139 return false;
140 }
is_loopback() const141 bool sockaddr_u::is_loopback() const
142 {
143 if(sa.sa_family==AF_INET)
144 {
145 unsigned char *a=(unsigned char *)&in.sin_addr;
146 return (a[0]==127 && a[1]==0 && a[2]==0 && a[3]==1);
147 }
148 #if INET6
149 if(sa.sa_family==AF_INET6)
150 return IN6_IS_ADDR_LOOPBACK(&in6.sin6_addr);
151 #endif
152 return false;
153 }
is_compatible(const sockaddr_u & o) const154 bool sockaddr_u::is_compatible(const sockaddr_u& o) const
155 {
156 return family()==o.family()
157 && !is_multicast() && !o.is_multicast()
158 && !is_reserved() && !o.is_reserved()
159 && is_private()==o.is_private()
160 && is_loopback()==o.is_loopback();
161 }
162
set_compact(const char * c,size_t len)163 bool sockaddr_u::set_compact(const char *c,size_t len)
164 {
165 if(len==4) {
166 sa.sa_family=AF_INET;
167 memcpy(&in.sin_addr,c,4);
168 in.sin_port=0;
169 return true;
170 #if INET6
171 } else if(len==16) {
172 sa.sa_family=AF_INET6;
173 memcpy(&in6.sin6_addr,c,16);
174 return true;
175 #endif
176 } else if(len==6) {
177 sa.sa_family=AF_INET;
178 memcpy(&in.sin_addr,c,4);
179 in.sin_port=htons((c[5]&255)|((c[4]&255)<<8));
180 return true;
181 #if INET6
182 } else if(len==18) {
183 sa.sa_family=AF_INET6;
184 memcpy(&in6.sin6_addr,c,16);
185 in6.sin6_port=htons((c[17]&255)|((c[16]&255)<<8));
186 return true;
187 #endif
188 }
189 return false;
190 }
compact() const191 const sockaddr_compact& sockaddr_u::compact() const
192 {
193 sockaddr_compact& c=compact_addr();
194 int p=port();
195 if(c.length() && p) {
196 c.append(char(p>>8));
197 c.append(char(p&255));
198 }
199 return c;
200 }
compact_addr() const201 sockaddr_compact& sockaddr_u::compact_addr() const
202 {
203 sockaddr_compact& c=sockaddr_compact::get_tmp();
204 if(family()==AF_INET)
205 c.append((const char*)&in.sin_addr,4);
206 #if INET6
207 else if(family()==AF_INET6)
208 c.append((const char*)&in6.sin6_addr,16);
209 #endif
210 return c;
211 }
212
NonBlock(int fd)213 void Networker::NonBlock(int fd)
214 {
215 int fl=fcntl(fd,F_GETFL);
216 fcntl(fd,F_SETFL,fl|O_NONBLOCK);
217 }
CloseOnExec(int fd)218 void Networker::CloseOnExec(int fd)
219 {
220 fcntl(fd,F_SETFD,FD_CLOEXEC);
221 }
222
223 static int one=1;
KeepAlive(int sock)224 void Networker::KeepAlive(int sock)
225 {
226 setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char*)&one,sizeof(one));
227 }
MinimizeLatency(int sock)228 void Networker::MinimizeLatency(int sock)
229 {
230 #ifdef IP_TOS
231 int tos = IPTOS_LOWDELAY;
232 setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int));
233 #endif
234 }
MaximizeThroughput(int sock)235 void Networker::MaximizeThroughput(int sock)
236 {
237 #ifdef IP_TOS
238 int tos = IPTOS_THROUGHPUT;
239 setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int));
240 #endif
241 }
ReuseAddress(int sock)242 void Networker::ReuseAddress(int sock)
243 {
244 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&one,sizeof(one));
245 }
SetSocketBuffer(int sock,int socket_buffer)246 void Networker::SetSocketBuffer(int sock,int socket_buffer)
247 {
248 if(socket_buffer==0)
249 return;
250 if(-1==setsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&socket_buffer,sizeof(socket_buffer)))
251 ProtoLog::LogError(1,"setsockopt(SO_SNDBUF,%d): %s",socket_buffer,strerror(errno));
252 if(-1==setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&socket_buffer,sizeof(socket_buffer)))
253 ProtoLog::LogError(1,"setsockopt(SO_RCVBUF,%d): %s",socket_buffer,strerror(errno));
254 }
SetSocketMaxseg(int sock,int socket_maxseg)255 void Networker::SetSocketMaxseg(int sock,int socket_maxseg)
256 {
257 #ifndef SOL_TCP
258 # define SOL_TCP IPPROTO_TCP
259 #endif
260 #ifdef TCP_MAXSEG
261 if(socket_maxseg==0)
262 return;
263 if(-1==setsockopt(sock,SOL_TCP,TCP_MAXSEG,(char*)&socket_maxseg,sizeof(socket_maxseg)))
264 ProtoLog::LogError(1,"setsockopt(TCP_MAXSEG,%d): %s",socket_maxseg,strerror(errno));
265 #endif
266 }
267
SocketCreateUnbound(int af,int type,int proto,const char * hostname)268 int Networker::SocketCreateUnbound(int af,int type,int proto,const char *hostname)
269 {
270 int s=socket(af,type,proto);
271 if(s<0)
272 return s;
273
274 NonBlock(s);
275 CloseOnExec(s);
276 SetSocketBuffer(s,ResMgr::Query("net:socket-buffer",hostname));
277 return s;
278 }
set_defaults(int af,const char * hostname,int port)279 bool sockaddr_u::set_defaults(int af,const char *hostname,int port)
280 {
281 memset(this,0,sizeof(*this));
282 sa.sa_family=af;
283 const char *b=0;
284 if(af==AF_INET)
285 {
286 b=ResMgr::Query("net:socket-bind-ipv4",hostname);
287 if(!(b && b[0] && inet_pton(af,b,&in.sin_addr)))
288 b=0;
289 in.sin_port=htons(port);
290 }
291 #if INET6
292 else if(af==AF_INET6)
293 {
294 b=ResMgr::Query("net:socket-bind-ipv6",hostname);
295 if(!(b && b[0] && inet_pton(af,b,&in6.sin6_addr)))
296 b=0;
297 in6.sin6_port=htons(port);
298 }
299 #endif
300 return b || port;
301 }
SocketBindStd(int s,int af,const char * hostname,int port)302 void Networker::SocketBindStd(int s,int af,const char *hostname,int port)
303 {
304 sockaddr_u bind_addr;
305 if(bind_addr.set_defaults(af,hostname,port))
306 {
307 if(bind_addr.bind_to(s)==-1)
308 ProtoLog::LogError(0,"bind(%s): %s",bind_addr.to_string(),strerror(errno));
309 }
310 }
SocketCreate(int af,int type,int proto,const char * hostname)311 int Networker::SocketCreate(int af,int type,int proto,const char *hostname)
312 {
313 int s=SocketCreateUnbound(af,type,proto,hostname);
314 if(s<0)
315 return s;
316 SocketBindStd(s,af,hostname);
317 return s;
318 }
SocketTuneTCP(int s,const char * hostname)319 void Networker::SocketTuneTCP(int s,const char *hostname)
320 {
321 KeepAlive(s);
322 SetSocketMaxseg(s,ResMgr::Query("net:socket-maxseg",hostname));
323 }
SocketCreateTCP(int af,const char * hostname)324 int Networker::SocketCreateTCP(int af,const char *hostname)
325 {
326 int s=SocketCreate(af,SOCK_STREAM,IPPROTO_TCP,hostname);
327 if(s<0)
328 return s;
329 SocketTuneTCP(s,hostname);
330 return s;
331 }
SocketCreateUnboundTCP(int af,const char * hostname)332 int Networker::SocketCreateUnboundTCP(int af,const char *hostname)
333 {
334 int s=SocketCreateUnbound(af,SOCK_STREAM,IPPROTO_TCP,hostname);
335 if(s<0)
336 return s;
337 SocketTuneTCP(s,hostname);
338 return s;
339 }
SocketConnect(int fd,const sockaddr_u * u)340 int Networker::SocketConnect(int fd,const sockaddr_u *u)
341 {
342 // some systems have wrong connect() prototype, so we have to cast off const.
343 // in any case, connect does not alter the address.
344 int res=connect(fd,(sockaddr*)&u->sa,SocketAddrLen(u));
345 if(res!=-1)
346 SMTask::UpdateNow(); // if non-blocking doesn't work
347 return res;
348 }
SocketAccept(int fd,sockaddr_u * u,const char * hostname)349 int Networker::SocketAccept(int fd,sockaddr_u *u,const char *hostname)
350 {
351 socklen_t len=sizeof(*u);
352 int a=accept(fd,&u->sa,&len);
353 if(a<0)
354 return a;
355 NonBlock(a);
356 CloseOnExec(a);
357 KeepAlive(a);
358 SetSocketBuffer(a,ResMgr::Query("net:socket-buffer",hostname));
359 SetSocketMaxseg(a,ResMgr::Query("net:socket-maxseg",hostname));
360 return a;
361 }
362
SocketSinglePF(int s,int pf)363 void Networker::SocketSinglePF(int s,int pf)
364 {
365 #if INET6 && defined(IPV6_V6ONLY)
366 if(pf==PF_INET6) {
367 int on = 1;
368 if(-1==setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)))
369 ProtoLog::LogError(1,"setsockopt(IPV6_V6ONLY): %s",strerror(errno));
370 }
371 #endif
372 }
373
374 #ifdef TIOCOUTQ
375 static bool TIOCOUTQ_returns_free_space;
376 static bool TIOCOUTQ_works;
377 static bool TIOCOUTQ_tested;
test_TIOCOUTQ()378 static void test_TIOCOUTQ()
379 {
380 int sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
381 if(sock==-1)
382 return;
383 TIOCOUTQ_tested=true;
384 int avail=-1;
385 socklen_t len=sizeof(avail);
386 if(getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&avail,&len)==-1)
387 avail=-1;
388 int buf=-1;
389 if(ioctl(sock,TIOCOUTQ,&buf)==-1)
390 buf=-1;
391 if(buf>=0 && avail>0 && (buf==0 || buf==avail))
392 {
393 TIOCOUTQ_works=true;
394 TIOCOUTQ_returns_free_space=(buf==avail);
395 }
396 close(sock);
397 }
398 #endif
SocketBuffered(int sock)399 int Networker::SocketBuffered(int sock)
400 {
401 #ifdef TIOCOUTQ
402 if(!TIOCOUTQ_tested)
403 test_TIOCOUTQ();
404 if(!TIOCOUTQ_works)
405 return 0;
406 int buffer=0;
407 if(TIOCOUTQ_returns_free_space)
408 {
409 socklen_t len=sizeof(buffer);
410 if(getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&buffer,&len)==-1)
411 return 0;
412 int avail=buffer;
413 if(ioctl(sock,TIOCOUTQ,&avail)==-1)
414 return 0;
415 if(avail>buffer)
416 return 0; // something wrong
417 buffer-=avail;
418 buffer=buffer*3/4; // approx...
419 }
420 else
421 {
422 if(ioctl(sock,TIOCOUTQ,&buffer)==-1)
423 return 0;
424 }
425 return buffer;
426 #else
427 return 0;
428 #endif
429 }
430
431 #ifdef HAVE_IFADDRS_H
432 #include <ifaddrs.h>
433 #endif
FindGlobalIPv6Address()434 const char *Networker::FindGlobalIPv6Address()
435 {
436 #if INET6 && defined(HAVE_IFADDRS_H)
437 struct ifaddrs *ifaddrs=0;
438 getifaddrs(&ifaddrs);
439 for(struct ifaddrs *ifa=ifaddrs; ifa; ifa=ifa->ifa_next) {
440 if(ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET6) {
441 struct in6_addr *addr=&((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
442 if(!IN6_IS_ADDR_UNSPECIFIED(addr) && !IN6_IS_ADDR_LOOPBACK(addr)
443 && !IN6_IS_ADDR_LINKLOCAL(addr) && !IN6_IS_ADDR_SITELOCAL(addr)
444 && !IN6_IS_ADDR_MULTICAST(addr)) {
445 char *buf=xstring::tmp_buf(INET6_ADDRSTRLEN);
446 inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
447 freeifaddrs(ifaddrs);
448 return buf;
449 }
450 }
451 }
452 freeifaddrs(ifaddrs);
453 #endif
454 return 0;
455 }
456
CanCreateIpv6Socket()457 bool Networker::CanCreateIpv6Socket()
458 {
459 #if INET6
460 bool can=true;
461 int s=socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP);
462 if(s==-1 && (errno==EINVAL
463 #ifdef EAFNOSUPPORT
464 || errno==EAFNOSUPPORT
465 #endif
466 ))
467 can=false;
468 if(s!=-1)
469 close(s);
470 return can;
471 #else
472 return false;
473 #endif
474 }
475