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