// 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); }