333 lines
12 KiB
C
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);
|
||
|
}
|
||
|
|
||
|
|