ipv6_address_utils.h
4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//
// ipv6_address_utils.h
//
// Created by cairui01 on 18/11/9.
// Copyright (c) 2018年 baidu. All rights reserved.
//
#ifndef comm_in6_v4mapped_macros_h
#define comm_in6_v4mapped_macros_h
#if !(defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
#include <netinet/in.h>
#include <unistd.h>
#include <string>
#include <net/if.h>
#include "unix_socket.h"
// Google DNS address used for IPv6 probes.
const uint8_t kIPv6ProbeAddress[] =
{ 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 };
// Baidu DND address used for IPv4 probes.
const uint8_t kIPv4ProbeAddress[] = {0xB4, 0x4C, 0x4C, 0x4C};
// By definition, socklen_t is large enough to hold both sizes.
const socklen_t kSockaddrIn6Size = sizeof(struct sockaddr_in6);
const socklen_t kSockaddrIn4Size = sizeof(struct sockaddr_in);
#ifndef __APPLE__
#define IN6ADDR_V4MAPPED_INIT {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}}}
#endif
#ifdef __APPLE__
#define s6_addr16 __u6_addr.__u6_addr16
#define s6_addr32 __u6_addr.__u6_addr32
#endif
#define IN6ADDR_NAT64_INIT {{{ 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
const in6_addr in6addr_v4mapped_init = IN6ADDR_V4MAPPED_INIT;
const in6_addr in6addr_nat64_init = IN6ADDR_NAT64_INIT;
inline void IN6_SET_ADDR_V4MAPPED(in6_addr* a6, const in_addr* a4) {
*a6 = in6addr_v4mapped_init;
a6->s6_addr32[3] = a4->s_addr;
}
inline void IN6_SET_ADDR_NAT64(in6_addr* a6, const in_addr* a4) {
*a6 = in6addr_nat64_init;
a6->s6_addr32[3] = a4->s_addr;
}
inline bool IN6_IS_ADDR_NAT64(const in6_addr* a6) {
return a6->s6_addr32[0] == htonl(0x0064ff9b);
}
#else
#include <mstcpip.h>
//TODO impl
#define IN6ADDR_NAT64_INIT {{{ 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
const in6_addr in6addr_nat64_init = IN6ADDR_NAT64_INIT;
#define s6_addr8 u.Byte
#define s6_addr16 u.Word
inline void IN6_SET_ADDR_NAT64(in6_addr* a6, const in_addr* a4) {
*a6 = in6addr_nat64_init;
a6->s6_bytes[12] = ((CONST UCHAR *) a4)[0];
a6->s6_bytes[13] = ((CONST UCHAR *) a4)[1];
a6->s6_bytes[14] = ((CONST UCHAR *) a4)[2];
a6->s6_bytes[15] = ((CONST UCHAR *) a4)[3];
}
inline bool IN6_IS_ADDR_NAT64(in6_addr* a6) {
return a6->s6_words[0] == htons(0x0064) && a6->s6_words[1] == htons(0x0064);
}
#endif
#endif
// Attempts to connect a UDP socket to |dest|:53 with specify interface.
inline bool isGloballyReachable(bool isIPv4, const std::string& interface_name = std::string()) {
int socketfd = INVALID_SOCKET;
int connectResult;
struct sockaddr* addr;
int interface_index = 0;
// Bind to Interface
if (!interface_name.empty()) {
interface_index = if_nametoindex(interface_name.c_str());
if (0 == interface_index) {
return false;
}
}
if (isIPv4) {
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
// Bind to Interface
if (INVALID_SOCKET != socketfd && !interface_name.empty()) {
if (0 != setsockopt(socketfd, IPPROTO_IP, IP_BOUND_IF, &interface_index, sizeof(interface_index))) {
return false;
}
}
struct sockaddr_in addr4;
memset(&addr4, 0, kSockaddrIn4Size);
addr4.sin_family = AF_INET;
uint16_t port = 53;
addr4.sin_port = port;
memcpy(&addr4.sin_addr, kIPv4ProbeAddress, 4);
addr = (sockaddr*)&addr4;
connectResult = connect(socketfd, addr, kSockaddrIn4Size);
} else {
socketfd = socket(AF_INET6, SOCK_DGRAM, 0);
// Bind to Interface
if (INVALID_SOCKET != socketfd && !interface_name.empty()) {
if (0 != setsockopt(socketfd, IPPROTO_IPV6, IPV6_BOUND_IF, &interface_index, sizeof(interface_index))) {
return false;
}
}
struct sockaddr_in6 addr6;
memset(&addr6, 0, kSockaddrIn6Size);
addr6.sin6_family = AF_INET6;
uint16_t port = 53;
addr6.sin6_port = port;
memcpy(&addr6.sin6_addr, kIPv6ProbeAddress, 16);
addr = (sockaddr*)&addr6;
connectResult = connect(socketfd, addr, kSockaddrIn6Size);
}
if (connectResult != 0) {
close(socketfd);
return false;
}
struct sockaddr localAddr;
socklen_t localAddrLen = sizeof(localAddr);
int socketNameResult = getsockname(socketfd, &localAddr, &localAddrLen);
if (socketNameResult != 0) {
close(socketfd);
return false;
}
close(socketfd);
return true;
}