getting done with primary function icmp_resolve, which will be used in cgo
This commit is contained in:
parent
4068b67077
commit
e1a5e8e29f
1 changed files with 87 additions and 30 deletions
117
main.c
117
main.c
|
|
@ -37,6 +37,11 @@ void print_mac(uint8_t* mac) {
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void output_mac(uint8_t* mac) {
|
||||||
|
printf("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* if_name;
|
char* if_name;
|
||||||
socklen_t if_len;
|
socklen_t if_len;
|
||||||
|
|
@ -49,6 +54,18 @@ typedef struct {
|
||||||
int if_mtu;
|
int if_mtu;
|
||||||
} linkinterface_t;
|
} linkinterface_t;
|
||||||
|
|
||||||
|
// because C has retarded array types
|
||||||
|
typedef struct {
|
||||||
|
uint8_t mac[ETH_ALEN];
|
||||||
|
} __attribute__((packed)) mac_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
uint32_t addr;
|
||||||
|
uint8_t octets[4];
|
||||||
|
};
|
||||||
|
} __attribute__((packed)) ip4addr_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
void* data;
|
void* data;
|
||||||
|
|
@ -131,7 +148,7 @@ void link_free(linkinterface_t* link) {
|
||||||
free(link);
|
free(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t link_send(linkinterface_t* link, const uint8_t* dstAddr,
|
ssize_t link_send(linkinterface_t* link, const mac_t* dstAddr,
|
||||||
uint16_t type, frame_t* frame)
|
uint16_t type, frame_t* frame)
|
||||||
{
|
{
|
||||||
// ETHER FRAME MUST NOT BE LESS THAN 64 (60)
|
// ETHER FRAME MUST NOT BE LESS THAN 64 (60)
|
||||||
|
|
@ -143,7 +160,7 @@ ssize_t link_send(linkinterface_t* link, const uint8_t* dstAddr,
|
||||||
|
|
||||||
struct ether_header* ether = (struct ether_header*)frame->data;
|
struct ether_header* ether = (struct ether_header*)frame->data;
|
||||||
memcpy(ether->ether_shost, link->host, ETH_ALEN);
|
memcpy(ether->ether_shost, link->host, ETH_ALEN);
|
||||||
memcpy(ether->ether_dhost, dstAddr, ETH_ALEN);
|
memcpy(ether->ether_dhost, dstAddr->mac, ETH_ALEN);
|
||||||
ether->ether_type = htons(type);
|
ether->ether_type = htons(type);
|
||||||
|
|
||||||
struct sockaddr_ll ll_addr = {0};
|
struct sockaddr_ll ll_addr = {0};
|
||||||
|
|
@ -159,9 +176,9 @@ ssize_t link_send(linkinterface_t* link, const uint8_t* dstAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t link_recv_any_from(linkinterface_t* link,
|
size_t link_recv_any_from(linkinterface_t* link,
|
||||||
const uint8_t** srcAddrs, unsigned addrNum,
|
const mac_t* srcAddrs, unsigned addrNum,
|
||||||
uint16_t type, frame_t* frame, unsigned timeoutMilis,
|
uint16_t type, frame_t* frame, unsigned timeoutMilis,
|
||||||
uint8_t* matchAddr)
|
mac_t* matchAddr)
|
||||||
{
|
{
|
||||||
clock_t beginTime = clock();
|
clock_t beginTime = clock();
|
||||||
clock_t deadline = beginTime + timeoutMilis;
|
clock_t deadline = beginTime + timeoutMilis;
|
||||||
|
|
@ -177,11 +194,11 @@ size_t link_recv_any_from(linkinterface_t* link,
|
||||||
|
|
||||||
unsigned matches = 0;
|
unsigned matches = 0;
|
||||||
for (unsigned i = 0; i < addrNum; i++) {
|
for (unsigned i = 0; i < addrNum; i++) {
|
||||||
if (!memcmp(ether->ether_shost, srcAddrs[i], ETH_ALEN)) {
|
if (!memcmp(ether->ether_shost, srcAddrs[i].mac, ETH_ALEN)) {
|
||||||
matches = 1;
|
matches = 1;
|
||||||
|
|
||||||
if (matchAddr) {
|
if (matchAddr) {
|
||||||
memcpy(matchAddr, ether->ether_shost, ETH_ALEN);
|
memcpy(matchAddr->mac, ether->ether_shost, ETH_ALEN);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -214,8 +231,8 @@ uint16_t checksum(const uint8_t* data, size_t len) {
|
||||||
return ~((uint16_t)sum);
|
return ~((uint16_t)sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t ip_send(linkinterface_t* link, const uint8_t* dstAddr,
|
ssize_t ip_send(linkinterface_t* link, const mac_t* dstAddr,
|
||||||
const uint8_t* dstIp, uint8_t proto, frame_t* frame)
|
const ip4addr_t dstIp, uint8_t proto, frame_t* frame)
|
||||||
{
|
{
|
||||||
// shift data to add space for IP header
|
// shift data to add space for IP header
|
||||||
size_t oldlen = frame->datalen;
|
size_t oldlen = frame->datalen;
|
||||||
|
|
@ -234,14 +251,14 @@ ssize_t ip_send(linkinterface_t* link, const uint8_t* dstAddr,
|
||||||
ip->ip_p = proto;
|
ip->ip_p = proto;
|
||||||
ip->ip_sum = 0;
|
ip->ip_sum = 0;
|
||||||
memcpy(&ip->ip_src, link->host_ip, 4);
|
memcpy(&ip->ip_src, link->host_ip, 4);
|
||||||
memcpy(&ip->ip_dst, dstIp, 4);
|
memcpy(&ip->ip_dst, dstIp.octets, 4);
|
||||||
// calculate header checksum
|
// calculate header checksum
|
||||||
ip->ip_sum = checksum((const uint8_t*)frame->data, sizeof(struct ip));
|
ip->ip_sum = checksum((const uint8_t*)frame->data, sizeof(struct ip));
|
||||||
|
|
||||||
return link_send(link, dstAddr, ETHERTYPE_IP, frame);
|
return link_send(link, dstAddr, ETHERTYPE_IP, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t icmp_direct_broadcast(linkinterface_t* link, const uint8_t* dstAddr, uint16_t seq) {
|
ssize_t icmp_direct_broadcast(linkinterface_t* link, const mac_t* dstAddr, uint16_t seq) {
|
||||||
size_t hdrlen = sizeof(struct icmphdr);
|
size_t hdrlen = sizeof(struct icmphdr);
|
||||||
const size_t payloadlen = 20;
|
const size_t payloadlen = 20;
|
||||||
|
|
||||||
|
|
@ -260,7 +277,7 @@ ssize_t icmp_direct_broadcast(linkinterface_t* link, const uint8_t* dstAddr, uin
|
||||||
|
|
||||||
icmp->checksum = checksum((const uint8_t*)frame->data, hdrlen + payloadlen);
|
icmp->checksum = checksum((const uint8_t*)frame->data, hdrlen + payloadlen);
|
||||||
|
|
||||||
const uint8_t ip_broadcast[4] = {255, 255, 255, 255};
|
const ip4addr_t ip_broadcast = { .addr = 0xFFFFFFFF };
|
||||||
size_t sent = ip_send(link, dstAddr, ip_broadcast, IPPROTO_ICMP, frame);
|
size_t sent = ip_send(link, dstAddr, ip_broadcast, IPPROTO_ICMP, frame);
|
||||||
|
|
||||||
frame_free(frame);
|
frame_free(frame);
|
||||||
|
|
@ -268,9 +285,9 @@ ssize_t icmp_direct_broadcast(linkinterface_t* link, const uint8_t* dstAddr, uin
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 - no match, 1 - matched
|
// 0 - no match, 1 - matched
|
||||||
unsigned icmp_match(linkinterface_t* link, const uint8_t** srcAddrs, unsigned addrNum,
|
unsigned icmp_match(linkinterface_t* link, const mac_t* srcAddrs, unsigned addrNum,
|
||||||
unsigned timeoutMillis,
|
unsigned timeoutMillis,
|
||||||
uint8_t* matchAddr, uint8_t* matchIp)
|
mac_t* matchAddr, ip4addr_t* matchIp)
|
||||||
{
|
{
|
||||||
frame_t* frame = frame_full(link);
|
frame_t* frame = frame_full(link);
|
||||||
size_t recv = link_recv_any_from(link, srcAddrs, addrNum,
|
size_t recv = link_recv_any_from(link, srcAddrs, addrNum,
|
||||||
|
|
@ -298,7 +315,7 @@ unsigned icmp_match(linkinterface_t* link, const uint8_t** srcAddrs, unsigned ad
|
||||||
// so ether frame directed to us, IP direct to us
|
// so ether frame directed to us, IP direct to us
|
||||||
// and ICMP is echo reply, therefore we sure
|
// and ICMP is echo reply, therefore we sure
|
||||||
// that we got right target IP
|
// that we got right target IP
|
||||||
memcpy(matchIp, &ip->ip_src.s_addr, 4);
|
memcpy(matchIp->octets, &ip->ip_src.s_addr, 4);
|
||||||
|
|
||||||
frame_free(frame);
|
frame_free(frame);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -308,8 +325,46 @@ _match_bad1:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns number of resolved IP addresses. `resolvedIps` must be capacity of addrNum,
|
||||||
|
// IPs set in the same order as targetAddrs ordered
|
||||||
|
unsigned icmp_resolve(linkinterface_t* link,
|
||||||
|
const mac_t* targetAddrs, unsigned addrNum,
|
||||||
|
unsigned timeoutMillis,
|
||||||
|
ip4addr_t* resolvedIps)
|
||||||
|
{
|
||||||
|
unsigned resolved = 0;
|
||||||
|
// sent ICMP packets
|
||||||
|
for (unsigned i = 0; i < addrNum; i++) {
|
||||||
|
if (icmp_direct_broadcast(link, &targetAddrs[i], 0) < 1) {
|
||||||
|
return -1; // bad link?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// receive ICMP packets as many as we match
|
||||||
|
clock_t deadline = clock() + timeoutMillis;
|
||||||
|
do {
|
||||||
|
mac_t matchAddr;
|
||||||
|
ip4addr_t matchIp;
|
||||||
|
|
||||||
|
if (icmp_match(link, targetAddrs, addrNum,
|
||||||
|
timeoutMillis, &matchAddr, &matchIp))
|
||||||
|
{
|
||||||
|
// find who we matched and place it in appropriate place
|
||||||
|
for (unsigned i = 0; i < addrNum; i++) {
|
||||||
|
if (!memcmp(targetAddrs[i].mac, matchAddr.mac, ETH_ALEN)) {
|
||||||
|
memcpy(resolvedIps[i].octets, matchIp.octets, 4);
|
||||||
|
resolved++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (resolved < addrNum && clock() < deadline);
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// ifname targetMAC
|
// ifname targetMAC1 targetMAC2 ...
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
linkinterface_t* link = link_open(argv[1]);
|
linkinterface_t* link = link_open(argv[1]);
|
||||||
if (!link) {
|
if (!link) {
|
||||||
perror("link_open");
|
perror("link_open");
|
||||||
|
|
@ -318,24 +373,26 @@ int main(int argc, char** argv) {
|
||||||
print_mac(link->host);
|
print_mac(link->host);
|
||||||
printf("MTU: %d\n", link->if_mtu);
|
printf("MTU: %d\n", link->if_mtu);
|
||||||
|
|
||||||
uint8_t target[ETH_ALEN];
|
unsigned targetNum = argc - 2;
|
||||||
parse_mac(argv[2], target);
|
mac_t* targets = (mac_t*)calloc(sizeof(mac_t), targetNum);
|
||||||
|
ip4addr_t* ips = (ip4addr_t*)calloc(sizeof(ip4addr_t), targetNum);
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
ssize_t sent = icmp_direct_broadcast(link, target, 0);
|
|
||||||
printf("sent %ld\n", sent);
|
|
||||||
|
|
||||||
const uint8_t* srcAddr = &target[0];
|
|
||||||
uint8_t matchAddr[ETH_ALEN], matchIp[4];
|
|
||||||
|
|
||||||
if (icmp_match(link, &srcAddr, 1, 5000, matchAddr, matchIp)) {
|
for (unsigned i = 0; i < targetNum; i++) {
|
||||||
printf("Got IP address of target: %d.%d.%d.%d\n",
|
parse_mac(argv[2 + i], targets[i].mac);
|
||||||
matchIp[0], matchIp[1], matchIp[2], matchIp[3]);
|
|
||||||
} else {
|
|
||||||
printf("Timeout");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned resolved = icmp_resolve(link, targets, targetNum, 5000, ips);
|
||||||
|
printf("Resolved: %u\n", resolved);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < resolved; i++) {
|
||||||
|
output_mac(targets[i].mac);
|
||||||
|
printf(" -> %d.%d.%d.%d\n", ips[i].octets[0],
|
||||||
|
ips[i].octets[1], ips[i].octets[2], ips[i].octets[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(targets);
|
||||||
|
free(ips);
|
||||||
|
|
||||||
link_free(link);
|
link_free(link);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue