mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-24 02:25:13 +00:00
Support raw mode for both IPv4 and IPv6
Read destination address of IP request packet and return it. Check length in client and use it as IPv4 or v6 depending on length.
This commit is contained in:
parent
7a51b22909
commit
b4e9148df8
@ -14,7 +14,8 @@ master:
|
|||||||
- Linux: use pkg-config for systemd support flags.
|
- Linux: use pkg-config for systemd support flags.
|
||||||
Patch by Jason A. Donenfeld.
|
Patch by Jason A. Donenfeld.
|
||||||
- Change external IP webservice to ipify.org
|
- Change external IP webservice to ipify.org
|
||||||
- Add support for IPv6 in the server. (Raw mode missing)
|
- Add support for IPv6 in the server.
|
||||||
|
Raw mode will be with same protocol as used for login.
|
||||||
Traffic inside tunnel is still IPv4.
|
Traffic inside tunnel is still IPv4.
|
||||||
|
|
||||||
2014-06-16: 0.7.0 "Kryoptonite"
|
2014-06-16: 0.7.0 "Kryoptonite"
|
||||||
|
@ -124,8 +124,7 @@ end of the tunnel. In this case, `ping 192.168.99.1` from the iodine client, and
|
|||||||
The data inside the tunnel is IPv4 only.
|
The data inside the tunnel is IPv4 only.
|
||||||
|
|
||||||
The server listens to both IPv4 and IPv6 for incoming requests. Raw mode
|
The server listens to both IPv4 and IPv6 for incoming requests. Raw mode
|
||||||
currently only works for IPv4, or can use IPv4 from IPv6 login if -n option is
|
will be attempted on the same protocol as used for the login.
|
||||||
used.
|
|
||||||
|
|
||||||
The client can use IPv4 or IPv6 nameservers to connect to iodined. The relay
|
The client can use IPv4 or IPv6 nameservers to connect to iodined. The relay
|
||||||
nameservers will translate between protocols automatically if needed. Use
|
nameservers will translate between protocols automatically if needed. Use
|
||||||
|
@ -38,7 +38,7 @@ Server replies:
|
|||||||
VFUL (server has no free slots), followed by max users
|
VFUL (server has no free slots), followed by max users
|
||||||
4 byte value: means login challenge/server protocol version/max users
|
4 byte value: means login challenge/server protocol version/max users
|
||||||
1 byte userid of the new user, or any byte if not VACK
|
1 byte userid of the new user, or any byte if not VACK
|
||||||
|
|
||||||
Login:
|
Login:
|
||||||
Client sends:
|
Client sends:
|
||||||
First byte l or L
|
First byte l or L
|
||||||
@ -50,17 +50,19 @@ Server replies:
|
|||||||
LNAK means not accepted
|
LNAK means not accepted
|
||||||
x.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits)
|
x.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits)
|
||||||
|
|
||||||
IP Request:
|
IP Request: (for where to try raw login)
|
||||||
Client sends:
|
Client sends:
|
||||||
First byte i or I
|
First byte i or I
|
||||||
5 bits coded as Base32 char, meaning userid
|
5 bits coded as Base32 char, meaning userid
|
||||||
CMC as 3 Base32 chars
|
CMC as 3 Base32 chars
|
||||||
Server replies
|
Server replies
|
||||||
BADIP if bad userid, or
|
BADIP if bad userid
|
||||||
I and then 4 bytes network order external IP address of iodined server
|
First byte I
|
||||||
|
Then comes external IP address of iodined server
|
||||||
|
as 4 bytes (IPv4) or 16 bytes (IPv6)
|
||||||
|
|
||||||
Upstream codec check / bounce:
|
Upstream codec check / bounce:
|
||||||
Client sends:
|
Client sends:
|
||||||
First byte z or Z
|
First byte z or Z
|
||||||
Lots of data that should not be decoded
|
Lots of data that should not be decoded
|
||||||
Server replies:
|
Server replies:
|
||||||
@ -100,7 +102,7 @@ Client sends:
|
|||||||
7: Base128 (a-zA-Z0-9\274-\375)
|
7: Base128 (a-zA-Z0-9\274-\375)
|
||||||
CMC as 3 Base32 chars
|
CMC as 3 Base32 chars
|
||||||
Server sends:
|
Server sends:
|
||||||
Name of codec if accepted. After this all upstream data packets must
|
Name of codec if accepted. After this all upstream data packets must
|
||||||
be encoded with the new codec.
|
be encoded with the new codec.
|
||||||
BADCODEC if not accepted. Client must then revert to previous codec
|
BADCODEC if not accepted. Client must then revert to previous codec
|
||||||
BADLEN if length of query is too short
|
BADLEN if length of query is too short
|
||||||
@ -182,7 +184,7 @@ GGGG = Downstream fragment number
|
|||||||
C = Compression enabled for downstream packet
|
C = Compression enabled for downstream packet
|
||||||
UDCMC = Upstream Data CMC, 36 steps a-z0-9, case-insensitive
|
UDCMC = Upstream Data CMC, 36 steps a-z0-9, case-insensitive
|
||||||
|
|
||||||
Upstream data packet starts with 1 byte ASCII hex coded user byte; then 3 bytes
|
Upstream data packet starts with 1 byte ASCII hex coded user byte; then 3 bytes
|
||||||
Base32 encoded header; then 1 char data-CMC; then comes the payload data,
|
Base32 encoded header; then 1 char data-CMC; then comes the payload data,
|
||||||
encoded with the chosen upstream codec.
|
encoded with the chosen upstream codec.
|
||||||
|
|
||||||
@ -225,8 +227,8 @@ always starting with the 2 bytes downstream data header as shown above.
|
|||||||
If server has nothing to send, no data is added after the header.
|
If server has nothing to send, no data is added after the header.
|
||||||
If server has something to send, it will add the downstream data packet
|
If server has something to send, it will add the downstream data packet
|
||||||
(or some fragment of it) after the header.
|
(or some fragment of it) after the header.
|
||||||
|
|
||||||
|
|
||||||
"Lazy-mode" operation
|
"Lazy-mode" operation
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@ -250,7 +252,7 @@ downstream data has to be sent.
|
|||||||
|
|
||||||
*: upstream data ack is usually done as reply on the previous ping packet,
|
*: upstream data ack is usually done as reply on the previous ping packet,
|
||||||
and the upstream-data packet itself is kept in queue.
|
and the upstream-data packet itself is kept in queue.
|
||||||
|
|
||||||
Client:
|
Client:
|
||||||
Downstream data is acked immediately, to keep it flowing fast (includes a
|
Downstream data is acked immediately, to keep it flowing fast (includes a
|
||||||
ping after last downstream frag).
|
ping after last downstream frag).
|
||||||
|
47
src/client.c
47
src/client.c
@ -64,7 +64,8 @@ static const char *password;
|
|||||||
|
|
||||||
static struct sockaddr_storage nameserv;
|
static struct sockaddr_storage nameserv;
|
||||||
static int nameserv_len;
|
static int nameserv_len;
|
||||||
static struct sockaddr_in raw_serv;
|
static struct sockaddr_storage raw_serv;
|
||||||
|
static int raw_serv_len;
|
||||||
static const char *topdomain;
|
static const char *topdomain;
|
||||||
|
|
||||||
static uint16_t rand_seed;
|
static uint16_t rand_seed;
|
||||||
@ -242,7 +243,7 @@ client_set_hostname_maxlen(int i)
|
|||||||
const char *
|
const char *
|
||||||
client_get_raw_addr()
|
client_get_raw_addr()
|
||||||
{
|
{
|
||||||
return inet_ntoa(raw_serv.sin_addr);
|
return format_addr(&raw_serv, raw_serv_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1488,8 +1489,10 @@ handshake_raw_udp(int dns_fd, int seed)
|
|||||||
int i;
|
int i;
|
||||||
int r;
|
int r;
|
||||||
int len;
|
int len;
|
||||||
unsigned remoteaddr = 0;
|
int got_addr;
|
||||||
struct in_addr server;
|
|
||||||
|
memset(&raw_serv, 0, sizeof(raw_serv));
|
||||||
|
got_addr = 0;
|
||||||
|
|
||||||
fprintf(stderr, "Testing raw UDP data to the server (skip with -r)");
|
fprintf(stderr, "Testing raw UDP data to the server (skip with -r)");
|
||||||
for (i=0; running && i<3 ;i++) {
|
for (i=0; running && i<3 ;i++) {
|
||||||
@ -1499,15 +1502,23 @@ handshake_raw_udp(int dns_fd, int seed)
|
|||||||
len = handshake_waitdns(dns_fd, in, sizeof(in), 'i', 'I', i+1);
|
len = handshake_waitdns(dns_fd, in, sizeof(in), 'i', 'I', i+1);
|
||||||
|
|
||||||
if (len == 5 && in[0] == 'I') {
|
if (len == 5 && in[0] == 'I') {
|
||||||
/* Received IP address */
|
/* Received IPv4 address */
|
||||||
remoteaddr = (in[1] & 0xff);
|
struct sockaddr_in *raw4_serv = (struct sockaddr_in *) &raw_serv;
|
||||||
remoteaddr <<= 8;
|
raw4_serv->sin_family = AF_INET;
|
||||||
remoteaddr |= (in[2] & 0xff);
|
memcpy(&raw4_serv->sin_addr, &in[1], sizeof(struct in_addr));
|
||||||
remoteaddr <<= 8;
|
raw4_serv->sin_port = htons(53);
|
||||||
remoteaddr |= (in[3] & 0xff);
|
raw_serv_len = sizeof(struct sockaddr_in);
|
||||||
remoteaddr <<= 8;
|
got_addr = 1;
|
||||||
remoteaddr |= (in[4] & 0xff);
|
break;
|
||||||
server.s_addr = ntohl(remoteaddr);
|
}
|
||||||
|
if (len == 17 && in[0] == 'I') {
|
||||||
|
/* Received IPv6 address */
|
||||||
|
struct sockaddr_in6 *raw6_serv = (struct sockaddr_in6 *) &raw_serv;
|
||||||
|
raw6_serv->sin6_family = AF_INET6;
|
||||||
|
memcpy(&raw6_serv->sin6_addr, &in[1], sizeof(struct in6_addr));
|
||||||
|
raw6_serv->sin6_port = htons(53);
|
||||||
|
raw_serv_len = sizeof(struct sockaddr_in6);
|
||||||
|
got_addr = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1518,19 +1529,13 @@ handshake_raw_udp(int dns_fd, int seed)
|
|||||||
if (!running)
|
if (!running)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!remoteaddr) {
|
if (!got_addr) {
|
||||||
fprintf(stderr, "Failed to get raw server IP, will use DNS mode.\n");
|
fprintf(stderr, "Failed to get raw server IP, will use DNS mode.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Server is at %s, trying raw login: ", inet_ntoa(server));
|
fprintf(stderr, "Server is at %s, trying raw login: ", format_addr(&raw_serv, raw_serv_len));
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
/* Store address to iodined server */
|
|
||||||
memset(&raw_serv, 0, sizeof(raw_serv));
|
|
||||||
raw_serv.sin_family = AF_INET;
|
|
||||||
raw_serv.sin_port = htons(53);
|
|
||||||
raw_serv.sin_addr = server;
|
|
||||||
|
|
||||||
/* do login against port 53 on remote server
|
/* do login against port 53 on remote server
|
||||||
* based on the old seed. If reply received,
|
* based on the old seed. If reply received,
|
||||||
* switch to raw udp mode */
|
* switch to raw udp mode */
|
||||||
|
@ -173,7 +173,7 @@ get_addr(char *host, int port, int addr_family, int flags, struct sockaddr_stora
|
|||||||
int
|
int
|
||||||
open_dns(struct sockaddr_storage *sockaddr, size_t sockaddr_len)
|
open_dns(struct sockaddr_storage *sockaddr, size_t sockaddr_len)
|
||||||
{
|
{
|
||||||
int flag = 1;
|
int flag;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if ((fd = socket(sockaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
if ((fd = socket(sockaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
||||||
@ -187,9 +187,6 @@ open_dns(struct sockaddr_storage *sockaddr, size_t sockaddr_len)
|
|||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
#ifndef WINDOWS32
|
||||||
/* To get destination address from each UDP datagram, see iodined.c:read_dns() */
|
|
||||||
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
|
|
||||||
|
|
||||||
fd_set_close_on_exec(fd);
|
fd_set_close_on_exec(fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
15
src/common.h
15
src/common.h
@ -53,14 +53,6 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
|
|||||||
|
|
||||||
#define QUERY_NAME_SIZE 256
|
#define QUERY_NAME_SIZE 256
|
||||||
|
|
||||||
#if defined IP_RECVDSTADDR
|
|
||||||
# define DSTADDR_SOCKOPT IP_RECVDSTADDR
|
|
||||||
# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x))
|
|
||||||
#elif defined IP_PKTINFO
|
|
||||||
# define DSTADDR_SOCKOPT IP_PKTINFO
|
|
||||||
# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined IP_MTU_DISCOVER
|
#if defined IP_MTU_DISCOVER
|
||||||
/* Linux */
|
/* Linux */
|
||||||
# define IP_OPT_DONT_FRAG IP_MTU_DISCOVER
|
# define IP_OPT_DONT_FRAG IP_MTU_DISCOVER
|
||||||
@ -95,12 +87,13 @@ struct query {
|
|||||||
unsigned short type;
|
unsigned short type;
|
||||||
unsigned short rcode;
|
unsigned short rcode;
|
||||||
unsigned short id;
|
unsigned short id;
|
||||||
struct in_addr destination;
|
struct sockaddr_storage destination;
|
||||||
|
socklen_t dest_len;
|
||||||
struct sockaddr_storage from;
|
struct sockaddr_storage from;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
unsigned short id2;
|
unsigned short id2;
|
||||||
struct sockaddr from2;
|
struct sockaddr_storage from2;
|
||||||
int fromlen2;
|
socklen_t fromlen2;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum connection {
|
enum connection {
|
||||||
|
102
src/iodined.c
102
src/iodined.c
@ -72,6 +72,18 @@ WSADATA wsa_data;
|
|||||||
|
|
||||||
#define PASSWORD_ENV_VAR "IODINED_PASS"
|
#define PASSWORD_ENV_VAR "IODINED_PASS"
|
||||||
|
|
||||||
|
#if defined IP_RECVDSTADDR
|
||||||
|
# define DSTADDR_SOCKOPT IP_RECVDSTADDR
|
||||||
|
# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x))
|
||||||
|
#elif defined IP_PKTINFO
|
||||||
|
# define DSTADDR_SOCKOPT IP_PKTINFO
|
||||||
|
# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IPV6_RECVPKTINFO
|
||||||
|
#define IPV6_RECVPKTINFO IPV6_PKTINFO
|
||||||
|
#endif
|
||||||
|
|
||||||
static int running = 1;
|
static int running = 1;
|
||||||
static char *topdomain;
|
static char *topdomain;
|
||||||
static char password[33];
|
static char password[33];
|
||||||
@ -917,9 +929,8 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
return;
|
return;
|
||||||
} else if(in[0] == 'I' || in[0] == 'i') {
|
} else if(in[0] == 'I' || in[0] == 'i') {
|
||||||
/* Request for IP number */
|
/* Request for IP number */
|
||||||
in_addr_t replyaddr;
|
char reply[17];
|
||||||
unsigned addr;
|
int length;
|
||||||
char reply[5];
|
|
||||||
|
|
||||||
userid = b32_8to5(in[1]);
|
userid = b32_8to5(in[1]);
|
||||||
if (check_authenticated_user_and_ip(userid, q) != 0) {
|
if (check_authenticated_user_and_ip(userid, q) != 0) {
|
||||||
@ -927,21 +938,24 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query
|
|||||||
return; /* illegal id */
|
return; /* illegal id */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns_ip != INADDR_ANY) {
|
reply[0] = 'I';
|
||||||
/* If set, use assigned external ip (-n option) */
|
if (q->from.ss_family == AF_INET) {
|
||||||
replyaddr = ns_ip;
|
if (ns_ip != INADDR_ANY) {
|
||||||
|
/* If set, use assigned external ip (-n option) */
|
||||||
|
memcpy(&reply[1], &ns_ip, sizeof(ns_ip));
|
||||||
|
} else {
|
||||||
|
/* otherwise return destination ip from packet */
|
||||||
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
memcpy(&reply[1], &addr->sin_addr, sizeof(struct in_addr));
|
||||||
|
}
|
||||||
|
length = 1 + sizeof(struct in_addr);
|
||||||
} else {
|
} else {
|
||||||
/* otherwise return destination ip from packet */
|
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &q->destination;
|
||||||
memcpy(&replyaddr, &q->destination.s_addr, sizeof(in_addr_t));
|
memcpy(&reply[1], &addr->sin6_addr, sizeof(struct in6_addr));
|
||||||
|
length = 1 + sizeof(struct in6_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = htonl(replyaddr);
|
write_dns(dns_fd, q, reply, length, 'T');
|
||||||
reply[0] = 'I';
|
|
||||||
reply[1] = (addr >> 24) & 0xFF;
|
|
||||||
reply[2] = (addr >> 16) & 0xFF;
|
|
||||||
reply[3] = (addr >> 8) & 0xFF;
|
|
||||||
reply[4] = (addr >> 0) & 0xFF;
|
|
||||||
write_dns(dns_fd, q, reply, sizeof(reply), 'T');
|
|
||||||
} else if(in[0] == 'Z' || in[0] == 'z') {
|
} else if(in[0] == 'Z' || in[0] == 'z') {
|
||||||
/* Check for case conservation and chars not allowed according to RFC */
|
/* Check for case conservation and chars not allowed according to RFC */
|
||||||
|
|
||||||
@ -1539,7 +1553,8 @@ handle_ns_request(int dns_fd, struct query *q)
|
|||||||
if (ns_ip != INADDR_ANY) {
|
if (ns_ip != INADDR_ANY) {
|
||||||
/* If ns_ip set, overwrite destination addr with it.
|
/* If ns_ip set, overwrite destination addr with it.
|
||||||
* Destination addr will be sent as additional record (A, IN) */
|
* Destination addr will be sent as additional record (A, IN) */
|
||||||
memcpy(&q->destination.s_addr, &ns_ip, sizeof(in_addr_t));
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain);
|
len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain);
|
||||||
@ -1566,12 +1581,14 @@ handle_a_request(int dns_fd, struct query *q, int fakeip)
|
|||||||
|
|
||||||
if (fakeip) {
|
if (fakeip) {
|
||||||
in_addr_t ip = inet_addr("127.0.0.1");
|
in_addr_t ip = inet_addr("127.0.0.1");
|
||||||
memcpy(&q->destination.s_addr, &ip, sizeof(in_addr_t));
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
memcpy(&addr->sin_addr, &ip, sizeof(ip));
|
||||||
|
|
||||||
} else if (ns_ip != INADDR_ANY) {
|
} else if (ns_ip != INADDR_ANY) {
|
||||||
/* If ns_ip set, overwrite destination addr with it.
|
/* If ns_ip set, overwrite destination addr with it.
|
||||||
* Destination addr will be sent as additional record (A, IN) */
|
* Destination addr will be sent as additional record (A, IN) */
|
||||||
memcpy(&q->destination.s_addr, &ns_ip, sizeof(in_addr_t));
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
len = dns_encode_a_response(buf, sizeof(buf), q);
|
len = dns_encode_a_response(buf, sizeof(buf), q);
|
||||||
@ -2038,7 +2055,7 @@ read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q)
|
|||||||
char packet[64*1024];
|
char packet[64*1024];
|
||||||
int r;
|
int r;
|
||||||
#ifndef WINDOWS32
|
#ifndef WINDOWS32
|
||||||
char address[96];
|
char control[CMSG_SPACE(sizeof (struct in6_pktinfo))];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
@ -2051,8 +2068,8 @@ read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q)
|
|||||||
msg.msg_namelen = (unsigned) addrlen;
|
msg.msg_namelen = (unsigned) addrlen;
|
||||||
msg.msg_iov = &iov;
|
msg.msg_iov = &iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
msg.msg_control = address;
|
msg.msg_control = control;
|
||||||
msg.msg_controllen = sizeof(address);
|
msg.msg_controllen = sizeof(control);
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
r = recvmsg(fd, &msg, 0);
|
r = recvmsg(fd, &msg, 0);
|
||||||
@ -2074,13 +2091,29 @@ read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
#ifndef WINDOWS32
|
||||||
|
memset(&q->destination, 0, sizeof(struct sockaddr_storage));
|
||||||
|
/* Read destination IP address */
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||||
|
|
||||||
if (cmsg->cmsg_level == IPPROTO_IP &&
|
if (cmsg->cmsg_level == IPPROTO_IP &&
|
||||||
cmsg->cmsg_type == DSTADDR_SOCKOPT) {
|
cmsg->cmsg_type == DSTADDR_SOCKOPT) {
|
||||||
|
|
||||||
q->destination = *dstaddr(cmsg);
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
|
addr->sin_addr = *dstaddr(cmsg);
|
||||||
|
q->dest_len = sizeof(*addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cmsg->cmsg_level == IPPROTO_IPV6 &&
|
||||||
|
cmsg->cmsg_type == IPV6_PKTINFO) {
|
||||||
|
|
||||||
|
struct in6_pktinfo *pktinfo;
|
||||||
|
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &q->destination;
|
||||||
|
pktinfo = (struct in6_pktinfo *) CMSG_DATA(cmsg);
|
||||||
|
addr->sin6_family = AF_INET6;
|
||||||
|
memcpy(&addr->sin6_addr, &pktinfo->ipi6_addr, sizeof(struct in6_addr));
|
||||||
|
q->dest_len = sizeof(*addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2311,6 +2344,24 @@ version() {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prepare_dns_fd(int fd)
|
||||||
|
{
|
||||||
|
#ifndef WINDOWS32
|
||||||
|
int flag = 1;
|
||||||
|
|
||||||
|
/* To get destination address from each UDP datagram, see read_dns() */
|
||||||
|
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void*) &flag, sizeof(flag));
|
||||||
|
#endif
|
||||||
|
#ifdef IPV6_PKTINFO
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, (const void*) &flag, sizeof(flag));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -2629,6 +2680,13 @@ main(int argc, char **argv)
|
|||||||
#ifdef HAVE_SYSTEMD
|
#ifdef HAVE_SYSTEMD
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Setup dns file descriptors to get destination IP address */
|
||||||
|
if (dns_fds.v4fd >= 0)
|
||||||
|
prepare_dns_fd(dns_fds.v4fd);
|
||||||
|
if (dns_fds.v6fd >= 0)
|
||||||
|
prepare_dns_fd(dns_fds.v6fd);
|
||||||
|
|
||||||
if (bind_enable) {
|
if (bind_enable) {
|
||||||
if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {
|
if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user