You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

276 lines
7.8 KiB

/*
* netutils.h - Network utilities
*
* Copyright (C) 2013 - 2019, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _NETUTILS_H
#define _NETUTILS_H
#ifdef __MINGW32__
#include "winsock.h"
#else
#include <sys/socket.h>
#endif
#include <netinet/in.h>
#ifdef HAVE_LINUX_TCP_H
#include <linux/tcp.h>
#elif HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#elif HAVE_NETDB_H
#include <netdb.h>
#endif
/* Hard coded defines for TCP fast open on Android */
#ifdef __ANDROID__
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
#endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#ifdef TCP_FASTOPEN_CONNECT
#undef TCP_FASTOPEN_CONNECT
#endif
#endif
#ifndef SO_REUSEPORT
#define SO_REUSEPORT 15
#endif
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif
#ifndef IP_RECVORIGDSTADDR
#ifdef IP_ORIGDSTADDR
#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR
#else
#define IP_RECVORIGDSTADDR 20
#endif
#endif
#ifndef IPV6_RECVORIGDSTADDR
#ifdef IPV6_ORIGDSTADDR
#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
#else
#define IPV6_RECVORIGDSTADDR 74
#endif
#endif
#ifndef IP6T_SO_ORIGINAL_DST
#define IP6T_SO_ORIGINAL_DST 80
#endif
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001UL
#endif
#define MAX_CONNECT_TIMEOUT 10
#define MAX_REQUEST_TIMEOUT 30
#define MIN_UDP_TIMEOUT 10
#ifdef MODULE_REMOTE
#define MAX_UDP_SOCKET_NUM 512
#else
#define MAX_UDP_SOCKET_NUM 256
#endif
#define DSCP_EF 0x2E
#define DSCP_MIN 0x0
#define DSCP_MAX 0x3F
#define DSCP_DEFAULT 0x0
#define DSCP_MIN_LEN 2
#define DSCP_MAX_LEN 4
#define DSCP_CS_LEN 3
#define DSCP_AF_LEN 4
#define MAX_HOSTNAME_LEN 256 // FQCN <= 255 characters
#define MAX_PORT_STR_LEN 6 // PORT < 65536
#ifndef BUF_SIZE
#define BUF_SIZE 65535
#endif
#define SOCKET_BUF_SIZE (16 * 1024 - 1) // 16383 Byte, equals to the max chunk size
#define STREAM_BUF_SIZE SOCKET_BUF_SIZE
#define DGRAM_PKT_SIZE 1397 // 1492 - DGRAM_PKT_HDR_SIZE = 1397, the default MTU for UDP relay
#define DGRAM_BUF_SIZE (DGRAM_PKT_SIZE * 2)
#define DGRAM_PKT_HDR_SIZE (1 + 28 + 2 + 64)
#define MAX_DGRAM_PKT_SIZE 65507
typedef struct {
uint8_t ss_family;
union {
struct in_addr addr;
struct in6_addr addr6;
} sin;
} ss_inaddr_t;
typedef enum {
PORT_SERVICE_UNKNOWN = -1,
PORT_DOMAIN_SERVICE,
PORT_HTTP_SERVICE,
PORT_HTTPS_SERVICE
} ss_service;
typedef struct {
ss_service service;
char **ports;
} ss_service_t;
struct cache *port_cache;
static const ss_service_t service_ports[] = {
{ .service = PORT_DOMAIN_SERVICE,
.ports = (char *[]) { "domain", NULL } },
{ .service = PORT_HTTP_SERVICE,
.ports = (char *[]) { "http", "http-alt", NULL } },
{ .service = PORT_HTTPS_SERVICE,
.ports = (char *[]) { "https", NULL } },
{ }
};
/**
* MPTCP_ENABLED
* ---------------------
* Enable multipath TCP for kernel version 3 and 4.
* The best way to maintain compatibility is to
* test from newest to the latest version and see if
* mptcp is enabled.
*/
#ifndef MPTCP_ENABLED
static const char mptcp_enabled_values[] = { 42, 26, 0 };
#else
static const char mptcp_enabled_values[] = { MPTCP_ENABLED, 0 };
#endif
#ifndef UPDATE_INTERVAL
#define UPDATE_INTERVAL 5
#endif
/** byte size of ipv4 address */
#define INET_SIZE 4
/** byte size of ipv6 address */
#define INET6_SIZE 16
#define inetaddr_selector(storage, addr, len) \
switch (storage->ss_family) { \
case AF_INET: { \
struct sockaddr_in *s = (sockaddr_in *)storage; \
len = sizeof(s->sin_addr); \
addr = &s->sin_addr; \
} break; \
case AF_INET6: { \
struct sockaddr_in6 *s = (sockaddr_in6 *)storage; \
len = sizeof(s->sin6_addr); \
addr = &s->sin6_addr; \
} break; \
}
#define inaddr_inc(addr, n) \
addr.s_addr = htonl(ntohl(addr.s_addr) + n);
#define in6addr_inc(addr, n) \
for (int i = 15; i >= 0; i--) { \
addr.s6_addr[i] += n; \
if (addr.s6_addr[i]) break; \
}
#define get_sockaddr(node, service, storage, resolv, ipv6first) \
get_sockaddr_r(node, service, 0, storage, resolv, ipv6first)
#define get_sockaddr_len(addr) \
(addr)->sa_family == AF_INET ? sizeof(struct sockaddr_in) : \
(addr)->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : 0
int get_sockaddr_r(const char *, const char *,
uint16_t, struct sockaddr_storage *, int, int);
int get_sockaddr_str(struct sockaddr_storage *storage,
char *host, char *port);
char *sockaddr_readable(char *format, struct sockaddr_storage *addr);
int tproxy_socket(int socket, int family);
int getdestaddr(int fd, struct sockaddr_storage *destaddr);
int getdestaddr_dgram(struct msghdr *msg, struct sockaddr_storage *destaddr);
int set_reuseport(int socket);
int set_mptcp(int socket);
int set_fastopen_passive(int socket);
#ifdef SET_INTERFACE
int setinterface(int socket_fd, const char *interface_name);
#endif
#ifndef __MINGW32__
int setnonblocking(int fd);
#endif
typedef struct listen_ctx listen_ctx_t;
int create_and_bind(struct sockaddr_storage *storage,
int protocol, listen_ctx_t *listen_ctx);
int bind_and_listen(struct sockaddr_storage *storage,
int protocol, listen_ctx_t *listen_ctx);
#ifdef HAVE_LAUNCHD
int launch_or_create(struct sockaddr_storage *storage,
int protocol, listen_ctx_t *listen_ctx);
#endif
ssize_t
sendto_idempotent(int fd, const void *buf, size_t len,
struct sockaddr *addr
#ifdef TCP_FASTOPEN_WINSOCK
, OVERLAPPED *olap, int *connect_ex_done
#endif
);
/**
* Compare two sockaddrs. Imposes an ordering on the addresses.
* Compares address and port.
* @param addr1: address 1.
* @param addr2: address 2.
* @param len: lengths of addr.
* @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
*/
int sockaddr_cmp(struct sockaddr_storage *addr1,
struct sockaddr_storage *addr2, socklen_t len);
/**
* Compare two sockaddrs. Compares address, not the port.
* @param addr1: address 1.
* @param addr2: address 2.
* @param len: lengths of addr.
* @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
*/
int sockaddr_cmp_addr(struct sockaddr_storage *addr1,
struct sockaddr_storage *addr2, socklen_t len);
int validate_hostname(const char *hostname, const int hostname_len);
char *hostname_readable(char *dname, uint16_t port);
int is_addr_loopback(const struct sockaddr *addr);
void parse_addr_cidr(const char *str, char *host, int *cidr);
int port_service(uint16_t port);
int port_service_init(void);
#endif