basics of ND with RADV
neighbor discovery protocol basics, just for fun and for radv slaac this is a working version, but code is not perfect, just commit to save the checkpoint -- this isn't the master, is it?
This commit is contained in:
parent
9beb97fdba
commit
5c7b1ffc99
31
ipv6.h
31
ipv6.h
@ -6,10 +6,13 @@ namespace ipv6 {
|
|||||||
const uint8_t LEN = 128;
|
const uint8_t LEN = 128;
|
||||||
const uint8_t ICMP_ECHO_REQUEST_TYPE = 128;
|
const uint8_t ICMP_ECHO_REQUEST_TYPE = 128;
|
||||||
const uint8_t ICMP_ECHO_REPLY_TYPE = 129;
|
const uint8_t ICMP_ECHO_REPLY_TYPE = 129;
|
||||||
|
const uint8_t ICMP_RADV_TYPE = 134;
|
||||||
|
|
||||||
const uint8_t NH_ICMP = 58;
|
const uint8_t NH_ICMP = 58;
|
||||||
const uint8_t NH_UDP = 17;
|
const uint8_t NH_UDP = 17;
|
||||||
|
|
||||||
|
extern uint8_t HOP_LIMIT;
|
||||||
|
|
||||||
class IPv6Addr {
|
class IPv6Addr {
|
||||||
private:
|
private:
|
||||||
char address[16];
|
char address[16];
|
||||||
@ -18,6 +21,7 @@ namespace ipv6 {
|
|||||||
IPv6Addr(const char* address);
|
IPv6Addr(const char* address);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const IPv6Addr LINK_LOCAL_ADDRESS;
|
||||||
extern const IPv6Addr ALL_NODES_ADDRESS;
|
extern const IPv6Addr ALL_NODES_ADDRESS;
|
||||||
|
|
||||||
struct ipv6_packet_header {
|
struct ipv6_packet_header {
|
||||||
@ -64,6 +68,33 @@ namespace ipv6 {
|
|||||||
const char* payload, /* IPv6 payload */
|
const char* payload, /* IPv6 payload */
|
||||||
int len /* IPv6 payload length */
|
int len /* IPv6 payload length */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
struct ICMPv6_RADV {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t code;
|
||||||
|
char checksum[2];
|
||||||
|
uint8_t cur_hop_limit;
|
||||||
|
uint8_t mo_flags;
|
||||||
|
uint16_t router_lifetime;
|
||||||
|
uint32_t reachable_time;
|
||||||
|
uint32_t retrans_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ICMPv6_RADV_Option {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ICMPv6_RADV_PrefixInformation {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t prefix_length;
|
||||||
|
uint8_t la_flags;
|
||||||
|
uint32_t valid_lifetime;
|
||||||
|
uint32_t preferred_lifetime;
|
||||||
|
uint32_t reserved2;
|
||||||
|
char prefix[16];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
98
ipv6.ino
98
ipv6.ino
@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
namespace ipv6 {
|
namespace ipv6 {
|
||||||
/******** costants ********/
|
/******** costants ********/
|
||||||
const IPv6Addr ALL_NODES_ADDRESS("\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"); /* ff02::1 */
|
const IPv6Addr ALL_NODES_ADDRESS("\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"); /* ff02::1 */
|
||||||
|
const IPv6Addr LINK_LOCAL_ADDRESS("\xfe\x80\x00\x00\x00\x00\x00\x00\xde\xad\xbe\xef\x12\x34\x56\x78"); /* fe80::dead:beef:1234:5678 */ /* TODO */
|
||||||
|
|
||||||
|
/******** variables ********/
|
||||||
|
uint8_t HOP_LIMIT = 64;
|
||||||
|
|
||||||
/******** buffer ********/
|
/******** buffer ********/
|
||||||
IPv6Packet packetin;
|
IPv6Packet packetin;
|
||||||
@ -60,7 +64,7 @@ IPv6Addr::IPv6Addr(const char* address) {
|
|||||||
IPv6Packet::IPv6Packet() {
|
IPv6Packet::IPv6Packet() {
|
||||||
memset(packet, 0, LEN);
|
memset(packet, 0, LEN);
|
||||||
*(packet) = 0x60; /* IP version 6 */
|
*(packet) = 0x60; /* IP version 6 */
|
||||||
*(packet + 7) = 64; /* hop limit / ttl */
|
*(packet + 7) = HOP_LIMIT; /* hop limit / ttl */
|
||||||
}
|
}
|
||||||
|
|
||||||
IPv6Packet::IPv6Packet(const char* buffer, int len) {
|
IPv6Packet::IPv6Packet(const char* buffer, int len) {
|
||||||
@ -112,8 +116,11 @@ void IPv6Packet::send() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IPv6Packet::doAction() {
|
void IPv6Packet::doAction() {
|
||||||
/* if destination is my address, or destination is "all nodes" address, then... */
|
/* if destination is my address (global or link-local), or destination is "all nodes" address, then... */
|
||||||
if ((memcmp(&(ALL_NODES_ADDRESS), packet + 24, 16) == 0) || (memcmp(&(coppino::address), packet + 24, 16) == 0)) {
|
if (
|
||||||
|
(memcmp(&(ALL_NODES_ADDRESS), packet + 24, 16) == 0) ||
|
||||||
|
(memcmp(&(LINK_LOCAL_ADDRESS), packet + 24, 16) == 0) ||
|
||||||
|
(memcmp(&(coppino::address), packet + 24, 16) == 0)) {
|
||||||
int ilen = this->getLen(); /* input payload length */
|
int ilen = this->getLen(); /* input payload length */
|
||||||
int olen; /* output payload length */
|
int olen; /* output payload length */
|
||||||
|
|
||||||
@ -148,41 +155,62 @@ void IPv6Packet::doAction() {
|
|||||||
int handleICMP(char* output_buffer, const char* input_buffer, int len) {
|
int handleICMP(char* output_buffer, const char* input_buffer, int len) {
|
||||||
uint8_t type = *(input_buffer);
|
uint8_t type = *(input_buffer);
|
||||||
|
|
||||||
if (type == ICMP_ECHO_REQUEST_TYPE) { /* if it is ICMPv6 Echo Request, then... */
|
/* compute checksum, and assert validity of incoming message */
|
||||||
/* compute checksum, and assert validity of incoming message */
|
char received_checksum[2];
|
||||||
char received_checksum[2];
|
memcpy(received_checksum, input_buffer + 2, 2);
|
||||||
memcpy(received_checksum, input_buffer + 2, 2);
|
|
||||||
|
|
||||||
memcpy(output_buffer, input_buffer, len);
|
memcpy(output_buffer, input_buffer, len);
|
||||||
memset(output_buffer + 2, 0, 2); /* zero-checksum */
|
memset(output_buffer + 2, 0, 2); /* zero-checksum */
|
||||||
uint16_t computed_checksum = compute_checksum(
|
uint16_t computed_checksum = compute_checksum(
|
||||||
packetin.getSrcAddress(),
|
packetin.getSrcAddress(),
|
||||||
packetin.getDstAddress(),
|
packetin.getDstAddress(),
|
||||||
NH_ICMP,
|
NH_ICMP,
|
||||||
len,
|
len,
|
||||||
output_buffer,
|
output_buffer,
|
||||||
len);
|
len);
|
||||||
|
|
||||||
if (memcmp(&computed_checksum, received_checksum, 2) == 0) { /* if checksum is valid, then... */
|
if (memcmp(&computed_checksum, received_checksum, 2) != 0) { /* if checksum is not valid, return */
|
||||||
/* Build an echo reply:
|
return -1;
|
||||||
* the reply has the same exact format of the request,
|
|
||||||
* except for Type and Checksum */
|
|
||||||
*(output_buffer) = ICMP_ECHO_REPLY_TYPE;
|
|
||||||
memset(output_buffer + 2, 0, 2); /* zero-checksum */
|
|
||||||
|
|
||||||
uint16_t checksum = compute_checksum(
|
|
||||||
packetin.getDstAddress(),
|
|
||||||
packetin.getSrcAddress(),
|
|
||||||
NH_ICMP,
|
|
||||||
len,
|
|
||||||
output_buffer,
|
|
||||||
len);
|
|
||||||
memcpy(output_buffer + 2, &checksum, 2);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == ICMP_ECHO_REQUEST_TYPE) { /* if it is ICMPv6 Echo Request, then... */
|
||||||
|
/* Build an echo reply:
|
||||||
|
* the reply has the same exact format of the request,
|
||||||
|
* except for Type and Checksum */
|
||||||
|
*(output_buffer) = ICMP_ECHO_REPLY_TYPE;
|
||||||
|
memset(output_buffer + 2, 0, 2); /* zero-checksum */
|
||||||
|
|
||||||
|
uint16_t checksum = compute_checksum(
|
||||||
|
packetin.getDstAddress(),
|
||||||
|
packetin.getSrcAddress(),
|
||||||
|
NH_ICMP,
|
||||||
|
len,
|
||||||
|
output_buffer,
|
||||||
|
len);
|
||||||
|
memcpy(output_buffer + 2, &checksum, 2);
|
||||||
|
return len;
|
||||||
|
|
||||||
|
} else if (type == ICMP_RADV_TYPE) { /* if it is IVMPc6 Router Advertisement, then... */
|
||||||
|
ICMPv6_RADV* radv = (ICMPv6_RADV*)input_buffer;
|
||||||
|
HOP_LIMIT = (radv->cur_hop_limit != 0) ? radv->cur_hop_limit : 64;
|
||||||
|
|
||||||
|
for (
|
||||||
|
ICMPv6_RADV_Option* option = (ICMPv6_RADV_Option*) (radv + 1);
|
||||||
|
option != input_buffer + len;
|
||||||
|
option = (ICMPv6_RADV_Option*) ( ((char*)(option)) + option->len )) {
|
||||||
|
digitalWrite(13, !digitalRead(13));
|
||||||
|
if (option->type == 3 && option->len == 4) { /* if it is a ICMPv6 Prefix Information, then... */
|
||||||
|
ICMPv6_RADV_PrefixInformation* p = (ICMPv6_RADV_PrefixInformation*) option;
|
||||||
|
|
||||||
|
if (p->prefix_length != 64) continue; /* only /64 prefix is supported */
|
||||||
|
if (! (p->la_flags & 0x40)) continue; /* only SLAAC is supported */
|
||||||
|
memcpy(&coppino::address, p->prefix, 8); /* set prefix -- leave host bits unchanged */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user