1 #define MODULE_LOG_PREFIX "net"
4 #include "oscam-client.h"
5 #include "oscam-failban.h"
6 #include "oscam-lock.h"
8 #include "oscam-string.h"
9 #include "oscam-time.h"
10 #include "oscam-work.h"
12 extern CS_MUTEX_LOCK gethostbyname_lock
;
13 extern int32_t exit_oscam
;
16 static int32_t inet_byteorder
= 0;
18 static in_addr_t
cs_inet_order(in_addr_t n
)
21 { inet_byteorder
= (inet_addr("1.2.3.4") + 1 == inet_addr("1.2.3.5")) ? 1 : 2; }
22 switch(inet_byteorder
)
27 n
= ((n
& 0xff000000) >> 24) |
28 ((n
& 0x00ff0000) >> 8) |
29 ((n
& 0x0000ff00) << 8) |
30 ((n
& 0x000000ff) << 24);
37 char *cs_inet_ntoa(IN_ADDR_T addr
)
40 static char buff
[INET6_ADDRSTRLEN
];
41 if(IN6_IS_ADDR_V4MAPPED(&addr
) || IN6_IS_ADDR_V4COMPAT(&addr
))
43 snprintf(buff
, sizeof(buff
), "%d.%d.%d.%d",
44 addr
.s6_addr
[12], addr
.s6_addr
[13], addr
.s6_addr
[14], addr
.s6_addr
[15]);
48 inet_ntop(AF_INET6
, &(addr
.s6_addr
), buff
, INET6_ADDRSTRLEN
);
54 return (char *)inet_ntoa(in
);
58 void cs_inet_addr(char *txt
, IN_ADDR_T
*out
)
61 char buff
[INET6_ADDRSTRLEN
];
62 //trying as IPv6 address
63 if(inet_pton(AF_INET6
, txt
, out
->s6_addr
) == 0)
65 //now trying as mapped IPv4
66 snprintf(buff
, sizeof(buff
), "::ffff:%s", txt
);
67 inet_pton(AF_INET6
, buff
, out
->s6_addr
);
70 *out
= inet_addr(txt
);
74 void cs_resolve(const char *hostname
, IN_ADDR_T
*ip
, struct SOCKADDR
*sock
, socklen_t
*sa_len
)
77 cs_getIPv6fromHost(hostname
, ip
, sock
, sa_len
);
79 *ip
= cs_getIPfromHost(hostname
);
81 { *sa_len
= sizeof(*sock
); }
86 int32_t cs_in6addr_equal(struct in6_addr
*a1
, struct in6_addr
*a2
)
88 return memcmp(a1
, a2
, 16) == 0;
91 int32_t cs_in6addr_lt(struct in6_addr
*a
, struct in6_addr
*b
)
94 for(i
= 0; i
< 4; i
++)
96 if((i
== 2) && ((IN6_IS_ADDR_V4COMPAT(a
) && IN6_IS_ADDR_V4MAPPED(b
)) ||
97 (IN6_IS_ADDR_V4COMPAT(b
) && IN6_IS_ADDR_V4MAPPED(a
))))
98 { continue; } // skip comparing this part
100 if(a
->s6_addr32
[i
] != b
->s6_addr32
[i
])
101 { return ntohl(a
->s6_addr32
[i
]) < ntohl(b
->s6_addr32
[i
]); }
107 int32_t cs_in6addr_isnull(struct in6_addr
*addr
)
110 for(i
= 0; i
< 16; i
++)
116 void cs_in6addr_copy(struct in6_addr
*dst
, struct in6_addr
*src
)
118 memcpy(dst
, src
, 16);
121 void cs_in6addr_ipv4map(struct in6_addr
*dst
, in_addr_t src
)
123 memset(dst
->s6_addr
, 0, 16);
124 dst
->s6_addr
[10] = 0xff;
125 dst
->s6_addr
[11] = 0xff;
126 memcpy(dst
->s6_addr
+ 12, &src
, 4);
130 IN_ADDR_T
get_null_ip(void)
134 cs_inet_addr("::", &ip
);
141 void set_null_ip(IN_ADDR_T
*ip
)
144 cs_inet_addr("::", ip
);
150 void set_localhost_ip(IN_ADDR_T
*ip
)
153 cs_inet_addr("::1", ip
);
155 cs_inet_addr("127.0.0.1", ip
);
159 int32_t check_ip(struct s_ip
*ip
, IN_ADDR_T n
)
164 for(p_ip
= ip
; (p_ip
) && (!ok
); p_ip
= p_ip
->next
)
166 ok
= cs_in6addr_lt(&n
, &p_ip
->ip
[0]);
167 ok
|= cs_in6addr_lt(&p_ip
->ip
[1], &n
);
171 for(p_ip
= ip
; (p_ip
) && (!ok
); p_ip
= p_ip
->next
)
172 { ok
= ((cs_inet_order(n
) >= cs_inet_order(p_ip
->ip
[0])) && (cs_inet_order(n
) <= cs_inet_order(p_ip
->ip
[1]))); }
177 /* Returns the ip from the given hostname. If gethostbyname is configured in the config file, a lock
178 will be held until the ip has been resolved. */
179 uint32_t cs_getIPfromHost(const char *hostname
)
182 // Resolve with gethostbyname:
183 if(cfg
.resolve_gethostbyname
)
185 cs_writelock(__func__
, &gethostbyname_lock
);
186 struct hostent
*rht
= gethostbyname(hostname
);
188 { cs_log("can't resolve %s", hostname
); }
190 { result
= ((struct in_addr
*)rht
->h_addr
)->s_addr
; }
191 cs_writeunlock(__func__
, &gethostbyname_lock
);
193 else // Resolve with getaddrinfo:
195 struct addrinfo hints
, *res
= NULL
;
196 memset(&hints
, 0, sizeof(hints
));
197 hints
.ai_socktype
= SOCK_STREAM
;
198 hints
.ai_family
= AF_INET
;
199 hints
.ai_protocol
= IPPROTO_TCP
;
201 int32_t err
= getaddrinfo(hostname
, NULL
, &hints
, &res
);
202 if(err
!= 0 || !res
|| !res
->ai_addr
)
204 cs_log("can't resolve %s, error: %s", hostname
, err
? gai_strerror(err
) : "unknown");
208 result
= ((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
.s_addr
;
210 if(res
) { freeaddrinfo(res
); }
216 void cs_getIPv6fromHost(const char *hostname
, struct in6_addr
*addr
, struct sockaddr_storage
*sa
, socklen_t
*sa_len
)
218 uint32_t ipv4addr
= 0;
219 struct addrinfo hints
, *res
= NULL
;
220 memset(&hints
, 0, sizeof(hints
));
221 hints
.ai_socktype
= SOCK_STREAM
;
222 hints
.ai_family
= AF_UNSPEC
;
223 hints
.ai_protocol
= IPPROTO_TCP
;
224 int32_t err
= getaddrinfo(hostname
, NULL
, &hints
, &res
);
225 if(err
!= 0 || !res
|| !res
->ai_addr
)
227 cs_log("can't resolve %s, error: %s", hostname
, err
? gai_strerror(err
) : "unknown");
231 ipv4addr
= ((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
.s_addr
;
232 if(res
->ai_family
== AF_INET
)
233 { cs_in6addr_ipv4map(addr
, ipv4addr
); }
235 { IP_ASSIGN(*addr
, SIN_GET_ADDR(*res
->ai_addr
)); }
237 { memcpy(sa
, res
->ai_addr
, res
->ai_addrlen
); }
239 { *sa_len
= res
->ai_addrlen
; }
242 { freeaddrinfo(res
); }
246 int set_socket_priority(int fd
, int priority
)
248 #if defined(IP_TOS) || defined(SO_PRIORITY)
249 if (priority
== 0) { return -1; } // default value, therefore leave it untouched (IPP=0; DSCP=CS0)
252 int cos
__attribute__ ((unused
)) = 0;
253 int tos
__attribute__ ((unused
)) = 0x00;
257 case 1: // IPP=1; DSCP=CS1
262 case 2: // IPP=1; DSCP=AF11
267 case 3: // IPP=1; DSCP=AF12
272 case 4: // IPP=1; DSCP=AF13
277 case 5: // IPP=2; DSCP=CS2
282 case 6: // IPP=2; DSCP=AF21
287 case 7: // IPP=2; DSCP=AF22
292 case 8: // IPP=2; DSCP=AF23
297 case 9: // IPP=3; DSCP=CS3
302 case 10: // IPP=3; DSCP=AF31
307 case 11: // IPP=3; DSCP=AF32
312 case 12: // IPP=3; DSCP=AF33
317 case 13: // IPP=4; DSCP=CS4
322 case 14: // IPP=4; DSCP=AF41
327 case 15: // IPP=4; DSCP=AF42
332 case 16: // IPP=4; DSCP=AF43
337 case 17: // IPP=5; DSCP=CS5
342 case 18: // IPP=5; DSCP=EF
347 case 19: // IPP=6; DSCP=CS6
352 case 20: // IPP=7; DSCP=CS7
359 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, (void *)&tos
, sizeof(tos
)) < 0)
361 cs_log("Setting IP_TOS failed, errno=%d, %s", errno
, strerror(errno
));
368 #if defined(IPV6SUPPORT) && defined(IPV6_TCLASS)
369 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, (void *)&tos
, sizeof(tos
)) < 0)
371 cs_log("Setting IPV6_TCLASS failed, errno=%d, %s", errno
, strerror(errno
));
381 if (setsockopt(fd
, SOL_SOCKET
, SO_PRIORITY
, (void *)&cos
, sizeof(cos
)) < 0)
383 cs_log("Setting SO_PRIORITY failed, errno=%d, %s", errno
, strerror(errno
));
399 void setTCPTimeouts(int32_t sock
)
402 // this is not only for a real keepalive but also to detect closed connections so it should not be configurable
403 if(setsockopt(sock
, SOL_SOCKET
, SO_KEEPALIVE
, &flag
, sizeof(flag
)) && errno
!= EBADF
)
405 cs_log("Setting SO_KEEPALIVE failed, errno=%d, %s", errno
, strerror(errno
));
408 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPCNT) && defined(TCP_KEEPINTVL)
411 if(setsockopt(sock
, IPPROTO_TCP
, TCP_KEEPIDLE
, &flag
, sizeof(flag
)) && errno
!= EBADF
) // send first keepalive packet after 10 seconds of last package received (keepalive packets included)
413 cs_log("Setting TCP_KEEPIDLE failed, errno=%d, %s", errno
, strerror(errno
));
418 if(setsockopt(sock
, IPPROTO_TCP
, TCP_KEEPCNT
, &flag
, sizeof(flag
)) && errno
!= EBADF
) // send up to 3 keepalive packets out (in interval TCP_KEEPINTVL), then disconnect if no response
420 cs_log("Setting TCP_KEEPCNT failed, errno=%d, %s", errno
, strerror(errno
));
425 if(setsockopt(sock
, IPPROTO_TCP
, TCP_KEEPINTVL
, &flag
, sizeof(flag
)) && errno
!= EBADF
)
427 ; // send a keepalive packet out every second (until answer has been received or TCP_KEEPCNT has been reached)
428 cs_log("Setting TCP_KEEPINTVL failed, errno=%d, %s", errno
, strerror(errno
));
436 if(setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(struct timeval
)) && errno
!= EBADF
)
439 cs_log("Setting SO_SNDTIMEO failed, errno=%d, %s", errno
, strerror(errno
));
445 if(setsockopt(sock
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(struct timeval
)) && errno
!= EBADF
)
448 cs_log("Setting SO_RCVTIMEO failed, errno=%d, %s", errno
, strerror(errno
));
451 #if defined(TCP_USER_TIMEOUT)
452 int timeout
= 60000; // RFC 5482 user timeout in milliseconds
453 setsockopt(sock
, SOL_TCP
, TCP_USER_TIMEOUT
, (char *) &timeout
, sizeof(timeout
));
457 int set_nonblock(int32_t fd
, bool nonblock
)
459 int32_t flags
= fcntl(fd
, F_GETFL
);
465 flags
&= (~O_NONBLOCK
);
466 return fcntl(fd
, F_SETFL
, flags
);
469 int8_t check_fd_for_data(int32_t fd
)
472 struct pollfd pfd
[1];
475 pfd
[0].events
= (POLLIN
| POLLPRI
);
476 rc
= poll(pfd
, 1, 0);
479 { cs_log("check_fd_for_data(fd=%d) failed: (errno=%d %s)", fd
, errno
, strerror(errno
)); }
481 if(rc
== -1 || rc
== 0)
484 if(pfd
[0].revents
& (POLLHUP
| POLLNVAL
| POLLERR
))
490 int32_t recv_from_udpipe(uint8_t *buf
)
495 cs_log("INTERNAL PIPE-ERROR");
498 memcpy(&n
, buf
+ 1, 2);
499 memmove(buf
, buf
+ 3, n
);
503 int32_t process_input(uint8_t *buf
, int32_t buflen
, int32_t timeout
)
505 int32_t rc
, i
, pfdcount
;
506 int64_t polltime
, timeoutms
;
507 struct pollfd pfd
[2];
508 struct s_client
*cl
= cur_client();
510 struct timeb starttime
;
511 struct timeb currenttime
;
512 timeoutms
= 1000 * timeout
;
513 cs_ftime(&starttime
);
514 polltime
= timeoutms
; // initial polltime = timeoutms
520 pfd
[pfdcount
].fd
= cl
->pfd
;
521 pfd
[pfdcount
++].events
= POLLIN
| POLLPRI
;
523 int32_t p_rc
= poll(pfd
, pfdcount
, polltime
);
525 cs_ftime(¤ttime
);
526 int64_t gone
= comp_timeb(¤ttime
, &starttime
);
527 polltime
= timeoutms
- gone
; // calculate polltime left
540 if((p_rc
== 0) && (timeout
!= 0) && (gone
>= timeoutms
)) // client maxidle reached? timeout = 0, idle disconnect disabled
546 for(i
= 0; i
< pfdcount
&& p_rc
> 0; i
++)
548 if(pfd
[i
].revents
& POLLHUP
) // POLLHUP is only valid in revents so it doesn't need to be set above in events
553 if(!(pfd
[i
].revents
& (POLLIN
| POLLPRI
)))
556 if(pfd
[i
].fd
== cl
->pfd
)
557 { return get_module(cl
)->recv(cl
, buf
, buflen
); }
563 static struct s_client
*find_client_by_ip(IN_ADDR_T ip
, in_port_t port
)
566 for(cl
= first_client
; cl
; cl
= cl
->next
)
568 if(!cl
->kill
&& IP_EQUAL(cl
->ip
, ip
) && cl
->port
== port
&& (cl
->typ
== 'c' || cl
->typ
== 'm'))
576 int32_t accept_connection(struct s_module
*module
, int8_t module_idx
, int8_t port_idx
)
579 int32_t scad
= sizeof(cad
), n
;
581 struct s_port
*port
= &module
->ptab
.ports
[port_idx
];
583 memset(&cad
, 0, sizeof(struct SOCKADDR
));
585 if(module
->type
== MOD_CONN_UDP
)
588 if(!cs_malloc(&buf
, 1024))
591 if((n
= recvfrom(port
->fd
, buf
+ 3, 1024 - 3, 0, (struct sockaddr
*)&cad
, (socklen_t
*)&scad
)) > 0)
594 cl
= find_client_by_ip(SIN_GET_ADDR(cad
), ntohs(SIN_GET_PORT(cad
)));
597 memcpy(buf
+ 1, &rl
, 2);
599 if(cs_check_violation(SIN_GET_ADDR(cad
), port
->s_port
))
605 cs_log_dbg(D_TRACE
, "got %d bytes on port %d from ip %s:%d client %s",
607 cs_inet_ntoa(SIN_GET_ADDR(cad
)), SIN_GET_PORT(cad
),
612 cl
= create_client(SIN_GET_ADDR(cad
));
613 if(!cl
) { return 0; }
615 cl
->module_idx
= module_idx
;
616 cl
->port_idx
= port_idx
;
617 cl
->udp_fd
= port
->fd
;
619 cl
->udp_sa_len
= sizeof(cl
->udp_sa
);
621 cl
->port
= ntohs(SIN_GET_PORT(cad
));
624 add_job(cl
, ACTION_CLIENT_INIT
, NULL
, 0);
626 add_job(cl
, ACTION_CLIENT_UDP
, buf
, n
+ 3);
634 if((pfd3
= accept(port
->fd
, (struct sockaddr
*)&cad
, (socklen_t
*)&scad
)) > 0)
637 if(cs_check_violation(SIN_GET_ADDR(cad
), port
->s_port
))
643 cl
= create_client(SIN_GET_ADDR(cad
));
651 setsockopt(pfd3
, IPPROTO_TCP
, TCP_NODELAY
, &flag
, sizeof(flag
));
652 setTCPTimeouts(pfd3
);
654 cl
->module_idx
= module_idx
;
656 cl
->port_idx
= port_idx
;
659 cl
->port
= ntohs(SIN_GET_PORT(cad
));
662 add_job(cl
, ACTION_CLIENT_INIT
, NULL
, 0);
668 void set_so_reuseport(int fd
) {
670 // See: http://stackoverflow.com/questions/3261965/so-reuseport-on-linux
672 setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&on
, sizeof(on
));
674 fd
= fd
; // Do nothing
678 int32_t start_listener(struct s_module
*module
, struct s_port
*port
)
680 int32_t ov
= 1, timeout
, is_udp
, i
;
682 struct SOCKADDR sad
; // structure to hold server's address
685 ptxt
[0][0] = ptxt
[1][0] = '\0';
688 cs_log_dbg(D_TRACE
, "%s: disabled", module
->desc
);
691 is_udp
= (module
->type
== MOD_CONN_UDP
);
693 memset(&sad
, 0 , sizeof(sad
));
695 SIN_GET_FAMILY(sad
) = AF_INET6
;
696 SIN_GET_ADDR(sad
) = in6addr_any
;
697 sad_len
= sizeof(struct sockaddr_in6
);
699 sad
.sin_family
= AF_INET
;
700 sad_len
= sizeof(struct sockaddr
);
703 { module
->s_ip
= cfg
.srvip
; }
707 sad
.sin_addr
.s_addr
= module
->s_ip
;
708 snprintf(ptxt
[0], sizeof(ptxt
[0]), ", ip=%s", inet_ntoa(sad
.sin_addr
));
712 sad
.sin_addr
.s_addr
= INADDR_ANY
;
716 timeout
= cfg
.bindwait
;
719 if(port
->s_port
> 0) // test for illegal value
721 SIN_GET_PORT(sad
) = htons((uint16_t)port
->s_port
);
725 cs_log("%s: Bad port %d", module
->desc
, port
->s_port
);
729 int s_type
= (is_udp
? SOCK_DGRAM
: SOCK_STREAM
);
730 int s_proto
= (is_udp
? IPPROTO_UDP
: IPPROTO_TCP
);
732 if((port
->fd
= socket(DEFAULT_AF
, s_type
, s_proto
)) < 0)
734 cs_log("%s: Cannot create socket (errno=%d: %s)", module
->desc
, errno
, strerror(errno
));
736 cs_log("%s: Trying fallback to IPv4", module
->desc
);
737 if((port
->fd
= socket(AF_INET
, s_type
, s_proto
)) < 0)
739 cs_log("%s: Cannot create socket (errno=%d: %s)", module
->desc
, errno
, strerror(errno
));
748 // azbox toolchain do not have this define
750 #define IPV6_V6ONLY 26
752 // set the server socket option to listen on IPv4 and IPv6 simultaneously
754 if(setsockopt(port
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (void *)&val
, sizeof(val
)) < 0)
756 cs_log("%s: setsockopt(IPV6_V6ONLY) failed (errno=%d: %s)", module
->desc
, errno
, strerror(errno
));
761 if(setsockopt(port
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&ov
, sizeof(ov
)) < 0)
763 cs_log("%s: setsockopt failed (errno=%d: %s)", module
->desc
, errno
, strerror(errno
));
769 set_so_reuseport(port
->fd
);
771 int prio_ret
= set_socket_priority(port
->fd
, cfg
.netprio
);
773 snprintf(ptxt
[1], sizeof(ptxt
[1]), ", prio=%d [%s%s%s ]", cfg
.netprio
, prio_ret
&0x04 ? " SO_PRIORITY" : "", prio_ret
&0x01 ? " IP_TOS" : "", prio_ret
&0x02 ? " IPV6_TCLASS" : "");
778 int32_t keep_alive
= 1;
779 setsockopt(port
->fd
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&keep_alive
, sizeof(keep_alive
));
782 while(timeout
-- && !exit_oscam
)
784 if(bind(port
->fd
, (struct sockaddr
*)&sad
, sad_len
) < 0)
788 cs_log("%s: Bind request failed (%s), waiting another %d seconds",
789 module
->desc
, strerror(errno
), timeout
);
794 cs_log("%s: Bind request failed (%s), giving up", module
->desc
, strerror(errno
));
808 if(listen(port
->fd
, CS_QLEN
) < 0)
810 cs_log("%s: Cannot start listen mode (errno=%d: %s)", module
->desc
, errno
, strerror(errno
));
817 cs_log("%s: initialized (fd=%d, port=%d%s%s)", module
->desc
, port
->fd
, port
->s_port
, ptxt
[0], ptxt
[1]);
819 for(i
= 0; port
->ncd
&& i
< port
->ncd
->ncd_ftab
.nfilts
; i
++)
822 char buf
[30 + (8 * port
->ncd
->ncd_ftab
.filts
[i
].nprids
)];
823 pos
+= snprintf(buf
, sizeof(buf
), "-> CAID: %04X PROVID: ", port
->ncd
->ncd_ftab
.filts
[i
].caid
);
825 for(j
= 0; j
< port
->ncd
->ncd_ftab
.filts
[i
].nprids
; j
++)
826 { pos
+= snprintf(buf
+ pos
, sizeof(buf
) - pos
, "%06X, ", port
->ncd
->ncd_ftab
.filts
[i
].prids
[j
]); }
829 { buf
[pos
- 2] = '\0'; }
839 * Workaround missing MSG_WAITALL implementation under Cygwin.
841 ssize_t
cygwin_recv(int sock
, void *buf
, int count
, int tflags
)
846 if ((n
= recv(sock
, bp
, count
, tflags
)) < 0)
851 if (n
< count
&& (tflags
& MSG_WAITALL
))
853 cs_log_dbg(D_TRACE
, "Cygwin socket read retry. Got %d expected %d", n
, count
);
855 int n2
= recv(sock
, bp
+ n
, count
- n
, tflags
);
856 if (n2
< 0 || n
+ n2
!= count
)
858 cs_log_dbg(D_TRACE
, "Cygwin socket read retry failed. Got %d", n2
);
866 cs_log_dbg(D_TRACE
, "Cygwin socket read retry success. Got %d - Total: %d", n2
, n
+ n2
);
874 #endif /* __CYGWIN__ */