code_production/cfg-tools/sdk/include/net/net_base.h

333 lines
12 KiB
C++

// net_base.h : network utility
//
// Author: Gongbing
//
// Create: 2019-07-18
#pragma once
//////////////////////////////////////////////////////////////////////////////////////////
// module type and global definition
#ifndef _INCLUDED_REF_
#define _INCLUDED_REF_
#include "../ref/ref.h"
#endif
#ifndef SOCKET
#define SOCKET unsigned int
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// import headers
//////////////////////////////////////////////////////////////////////////////////////////
// structures && enumerations
#define IP_BUF_LEN 48
typedef struct _ip_info
{
int index; // NIC index
char ip[IP_BUF_LEN];
char gateway[IP_BUF_LEN];
char subnet[IP_BUF_LEN];
}IPINFO, *LPIPINFO;
enum firewall_port_cat
{
FWPORT_UNKNOWN = 0,
FWPORT_TCP,
FWPORT_UDP,
FWPORT_ALL,
};
#pragma pack(push)
#pragma pack(1)
typedef struct _ip_pack
{
// all in net-sn, i.e. big-endian
unsigned long ver : 4; // version of the ip-datagram
unsigned long head_len : 4; // length in four-bytes of this head, unit as long
unsigned long service : 8; // service type ...
unsigned long total_len : 16; // total bytes of this datagram, include this header
unsigned long mark : 16;
unsigned long flag : 3;
unsigned long offset : 13; // offet of part data in whole data
unsigned long ttl : 8; // living time, as hops
unsigned long protocol : 8; // protocol type, see IPPROTO_ICMP ...
unsigned long checksum : 16; //
unsigned long src_ip;
unsigned long dst_ip;
unsigned char head_data[0];
void from_buffer(const unsigned char* buf)
{
ver = *buf >> 4;
head_len = *buf++;
service = *buf++;
total_len = *buf++;
total_len <<= 8;
total_len |= *buf++;
mark = *buf++;
mark <<= 8;
mark |= *buf++;
flag = *buf >> 5;
offset = *buf & 0x1f;
offset <<= 8;
offset |= buf[1];
buf += 2;
ttl = *buf++;
protocol = *buf++;
checksum = *buf++;
checksum <<= 8;
checksum |= *buf++;
src_ip = *buf++;
src_ip <<= 8;
src_ip |= *buf++;
src_ip <<= 8;
src_ip |= *buf++;
src_ip <<= 8;
src_ip |= *buf++;
dst_ip = *buf++;
dst_ip <<= 8;
dst_ip |= *buf++;
dst_ip <<= 8;
dst_ip |= *buf++;
dst_ip <<= 8;
dst_ip |= *buf++;
// data, you should ensure enough buffer to contains it !!!
int rest = head_len * 4 - sizeof(*this);
if (rest > 0)
memcpy(head_data, buf, rest);
}
unsigned long calc_checksum(void)
{
unsigned long chk = 0;
// 1 - fixed fields:
chk = (ver << 12) | (head_len << 8) | service;
chk += total_len;
chk += mark;
chk += (flag << 13) | offset;
chk += (ttl << 8) | protocol;
chk += src_ip & 0x0ffff;
chk += src_ip >> 16;
chk += dst_ip & 0x0ffff;
chk += dst_ip >> 16;
// 2 - appendix data in header:
unsigned short *d = (unsigned short*)head_data;
int num = (head_len * 4 - sizeof(*this)) / 2;
for (int i = 0; i < num; ++i)
chk += *d++;
// 3 - add the overflow of short
chk = (chk & 0x0ffff) + (chk >> 16);
chk = (chk & 0x0ffff) + (chk >> 16);
// 4 - NOT
checksum = ~chk;
return checksum;
}
int to_buffer(unsigned char* buf)
{
calc_checksum();
*buf++ = (ver << 4) | head_len;
*buf++ = service;
*buf++ = total_len >> 8;
*buf++ = total_len;
*buf++ = mark >> 8;
*buf++ = mark;
*buf++ = (flag << 5) | (offset >> 8);
*buf++ = offset;
*buf++ = ttl;
*buf++ = protocol;
*buf++ = checksum >> 8;
*buf++ = checksum;
*buf++ = src_ip >> 24;
*buf++ = src_ip >> 16;
*buf++ = src_ip >> 8;
*buf++ = src_ip;
*buf++ = dst_ip >> 24;
*buf++ = dst_ip >> 16;
*buf++ = dst_ip >> 8;
*buf++ = dst_ip;
int rest = head_len * 4 - sizeof(*this);
if (rest > 0)
memcpy(buf, head_data, rest);
return head_len * 4;
}
}IPPACK, *LPIPPACK;
enum _icmp_type
{
ICMP_TYPE_TERM_UNREACHABLE = 3, // the terminal is unreachable
ICMP_TYPE_RESTRICT_SOURCE,
ICMP_TYPE_MODIFY_ROUTER,
ICMP_TYPE_TIMEOUT = 11, // when ttl == 0, send back this type by router
ICMP_TYPE_INVALID_PARAMETER,
ICMP_TYPE_ECHO_ANSWER = 0, // answer for query request
ICMP_TYPE_ECHO_REQUEST = 8,
ICMP_TYPE_TIMESTAMP_REQUEST = 13,
ICMP_TYPE_TIMESTAMP_ANSWER,
};
enum _term_unrechable_code
{
TERM_UNREACHABLE_NETWORK = 0,
TERM_UNREACHABLE_TERMINAL,
TERM_UNREACHABLE_PROTOCOL,
TERM_UNREACHABLE_PORT,
TERM_UNREACHABLE_DATA_SEGMENT, // data should divided into several segments
TERM_UNREACHABLE_SOURCE_ROUTER, // source router cannot complete
TERM_UNREACHABLE_UNKNOWN_DST_NET, // destination network is unknown
TERM_UNREACHABLE_UNKNOWN_TERMINAL,
TERM_UNREACHABLE_SOURCE_DISABLED, // source host is disabled
TERM_UNREACHABLE_DISABLE_NETWORK, // disabled with network by policy
TERM_UNREACHABLE_DISABLE_TERM, // disabled with destion terminal by policy
TERM_UNREACHABLE_SERVICE_NETWORK, // network cannot support the service
TERM_UNREACHABLE_SERVICE_TERM, // destion terminal cannot support the service
TERM_UNREACHABLE_TERM_FILTER, // destion terminal has filter
TERM_UNREACHABLE_TERM_PRIORITY, // confilict with priority policy
TERM_UNREACHABLE_PRIORITY_DISABLED, //
};
enum _modi_router_code
{
MODI_ROUTER_FOR_NETWORK = 0, // modify the router-table for given network
MODI_ROUTER_FOR_TERM, // modify the router-table for given terminal
MODI_ROUTER_FOR_SERVICE_NETWORK, // modify the router-table for given network on given service
MODI_ROUTER_FOR_SERVICE_TERM, // modify the router-table for given termina on given service
};
typedef struct _icmp_pack
{
unsigned char type;
unsigned char code;
unsigned short checksum;
unsigned short mark;
unsigned short seq;
void from_buffer(const unsigned char* buf)
{
type = *buf++;
code = *buf++;
checksum = (buf[0] << 8) | buf[1];
buf += 2;
mark = (buf[0] << 8) | buf[1];
buf += 2;
seq = (buf[0] << 8) | buf[1];
}
void to_buffer(unsigned char* buf)
{
*buf++ = type;
*buf++ = code;
*buf++ = checksum >> 8;
*buf++ = checksum;
*buf++ = mark >> 8;
*buf++ = mark;
*buf++ = seq >> 8;
*buf++ = seq;
}
}ICMPPACK, *LPICMPPACK;
#pragma pack(pop)
//////////////////////////////////////////////////////////////////////////////////////////
// apis
namespace net_base_util
{
PORT_API(void) free_sock_addr(void* sockaddr);
PORT_API(void*) init_sock_addr(const char* ip, unsigned port, int* addrlen, int family = /*AF_INET*/2, int type = /*SOCK_STREAM*/1, int proto = /*IPPROTO_TCP*/6); // return sockaddr_in* type. call net_base_util::free_sock_addr to free the returned value !!!
PORT_API(void) ipv4_broadcast_address(unsigned self_ip, unsigned subnet, char ipbuf[IP_BUF_LEN]);
PORT_API(bool) ip_from_sockaddr_storage(const void/*sockaddr_storage*/* sockaddr_storage_, char ipbuf[IP_BUF_LEN], unsigned* port);
PORT_API(bool) is_ip_equal(const void/*sockaddr_storage*/* sockaddr_storage1_, const void/*sockaddr_storage*/* sockaddr_storage2_, bool compare_port = false);
// following apis return as base-socket api
PORT_API(int) init_network(unsigned min_ver = 2, unsigned max_ver = 2);
PORT_API(int) cleanup_network(void);
PORT_API(SOCKET) raw_socket(int raw_proto, bool overlapped = false, bool ipv6 = false);
PORT_API(SOCKET) tcp_socket(bool overlapped = false, bool ipv6 = false);
PORT_API(SOCKET) udp_socket(bool overlapped = false, bool ipv6 = false, bool broadcast = false);
PORT_API(int) close_socket(SOCKET s);
PORT_API(int) bind_socket(SOCKET s, bool ipv6_socket, const char* ip, unsigned port);
PORT_API(int) ip_from_domain(const char* domain, char ipbuf[IP_BUF_LEN]);
PORT_API(int) get_local_ip(LPIPINFO ips, size_t* count/*[in] - count of ips; [out] - ip numbers in ips*/);
PORT_API(int) get_ipv6_addrress(LPIPINFO ips, size_t* count/*[in] - count of ips; [out] - ip numbers in ips*/, const char* hostname = NULL/*local ipv6 when NULL*/);
PORT_API(int) set_socket_block(SOCKET s, bool blocked);
PORT_API(int) set_socket_buffer(SOCKET s, int buf_size, bool in_buf/*true for in buffer and false for out buffer*/);
PORT_API(int) set_socket_keepalive(SOCKET s, bool keep_alive);
PORT_API(int) set_socket_keepalive_detect(SOCKET s, bool detect_on, int alive_heart_milliseconds = 0, int retry_heart_milliseconds = 0);
PORT_API(int) set_socket_timeout(SOCKET s, int milliseconds = 0/*no timeout*/, bool rcv_timeout = true);
PORT_API(int) get_socket_timeout(SOCKET s, int *milliseconds, bool rcv_timeout);
PORT_API(int) set_socket_nagle(SOCKET s, bool nagle_on); // if nagle_on is true, then the packet maybe sent delayed
PORT_API(int) set_socket_ttl(SOCKET s, unsigned short ttl);
PORT_API(int) set_reused_address(SOCKET s, bool reused);
PORT_API(int) set_broadcast(SOCKET s, bool enabled);
PORT_API(int) connect_with_timeout(SOCKET s, const char* ip, unsigned port, unsigned timeout_seconds, bool return_block_socket = false);
PORT_API(SOCKET) connect_2_server(const char* ip, unsigned short port, unsigned timeout_seconds = 0/*0 to blocked*/, bool return_block_socket = false, const char* bind_ip = NULL, unsigned bind_port = 0);
// following apis return 0 for success otherwise error code
PORT_API(int) ipv4_broadcast_address(const char* self_ip, const char* subnet, char ip_buf[IP_BUF_LEN]);
PORT_API(int) get_peer_address(SOCKET s, bool remote, unsigned* port, char ip_buf[IP_BUF_LEN]);
PORT_API(int) ipv4_address(unsigned addr, char ip_buf[IP_BUF_LEN]);
PORT_API(unsigned) ipv4_address(const char* ipv4);
PORT_API(bool) is_in_same_ipv4_subnet(const char* ip1, const char* ip2, const char* subnet);
// parameters of result:
// data: (const char*)adapter_name
// data_len: (const char*)adapter_description
// total_len: IPINFO*
// flag: inter_module_data::DATA_FLAG_FINAL
// param: the same as 'param'
PORT_API(int) enum_network_adapters(inter_module_data::set_data result, void* param);
// parameters of result:
// data: (const char*)local address
// data_len: (const char*)remote address
// total_len: HIDWORD = state, LODWORD = owning pid
// flag: inter_module_data::DATA_FLAG_FINAL
// param: the same as 'param'
PORT_API(int) enum_sockets(bool tcp, inter_module_data::set_data result, void* param);
// trace route by raw socket with ICMP
// parameter of result:
// data: ip, NULL when over
// len: milliseconds, -1 is timeout, or error code when over
// total: hops count, unused when over
// flag: DATA_FLAG_FINAL in hops, DATA_FLAG_INSTAR in beginning information, and DATA_FLAG_OVER for over
// param: 'param'
// PORT_API(int) trace_route(const char* www, inter_module_data::set_data result, void* param, int max_hops = 30); // commented, use net_app::trace_route
PORT_API(unsigned) proto_default_port(const char* proto);
// function: get the next hop, generally as gateway
// for_ip: in multi-network-card, get the the next hop for given ip, if was NULL, return the first
PORT_API(int) get_next_hop(char next_hop[IP_BUF_LEN], const char* for_ip = NULL);
// Note: the buffer length of proto(proto_buf_len) must be double of url!!! for host and page would use the buffer
// and need not free host and page
PORT_API(bool) parse_url(const char* url, char* proto, size_t proto_buf_len, char** host, char** page, unsigned* port, bool* port_from_host = NULL);
PORT_API(bool) parse_url(const wchar_t* url, wchar_t* proto, size_t proto_buf_len, wchar_t** host, wchar_t** page, unsigned* port, bool* port_from_host = NULL);
PORT_API(unsigned short) calculate_ip_datagram_checksum(const unsigned char* buf, int bytes, bool* ok = NULL);
PORT_API(unsigned short) calculate_icmp_checksum(LPICMPPACK pack, int bytes, bool* ok = NULL);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// windows firewall
PORT_API(bool) firewall_is_on(void);
PORT_API(bool) firewall_is_app_enabled(const wchar_t* app_pe_name);
PORT_API(bool) firewall_is_port_enabled(unsigned port, firewall_port_cat fpc);
PORT_API(int) firewall_turn_on(void);
PORT_API(int) firewall_turn_off(void);
PORT_API(int) firewall_enable_app(const wchar_t* name/*display name in firewall*/, const wchar_t* pe/*pe-image file name*/, bool enable);
PORT_API(int) firewall_enable_port(unsigned port, firewall_port_cat fpc, bool enable, const wchar_t* name/*display name in firewall*/ = NULL);
}