Get Peer IP Address and Port - c

I manage to get the host information from particular requested network adapter using code below but i have no idea how to get peer ip address from host ip address.
struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
ipAddr = ntohl(*((u_int32_t *)&sa->sin_addr));
if (pIpAddr != NULL)
{
*pIpAddr = ipAddr;
}
// Get the MAC address
if ( ioctl(s, SIOCGIFHWADDR, item) < 0 )
{
printf("_GetMacAddress : SIOCGIFHWADDR failed!\n");
return 0;
}
else
{
struct sockaddr *eth = (struct sockaddr *) &item->ifr_ifru.ifru_hwaddr;
unsigned long *low = (unsigned long *)&eth->sa_data[2];
unsigned short *high = (unsigned short*)&eth->sa_data[0];
//printf("%s : MAC = 0x%04x, 0x%08x", ntohs(*high), ntohl(*low));
printf("Interface %8s : IP %3d.%3d.%3d.%3d : MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",
item->ifr_name,
((ipAddr >> 24)&0xff), ((ipAddr >> 16)&0xff), ((ipAddr >> 8)&0xff), (ipAddr&0xff),
((ntohs(*high)>> 8)&0x00ff), (ntohs(*high)&0x00ff),
((ntohl(*low)>> 24)&0x00ff), ((ntohl(*low)>> 16)&0x00ff), ((ntohl(*low)>> 8)&0x00ff), (ntohl(*low)&0x00ff));
if ((pMacHigh != NULL) && (pMacLow != NULL))
{
*pMacHigh = *high;
*pMacLow = *low;
}
}
The output is:
_GetMaxNetworkInterfaces 3
Interface lo : IP 127. 0. 0. 1 : MAC = 00:00:00:00:00:00
Interface enp4s0 : IP 192.168.128. 88 : MAC = f4:8e:38:ea:88:23
Interface wlp5s0 : IP 192.168. 53. 63 : MAC = b8:81:98:b7:71:90

If you are server listening for incoming connection, you can get peer address from accept() , in the second its argument, when a new socket is accepted
From man page of accept():
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the peer socket, as known to the communications layer. The exact format of the address returned addr is determined by the socket's address family (see socket(2) and the respective protocol man pages). When addr is NULL, nothing is filled in; in this case, addrlen is not used, and should also be NULL.

I have no idea how to get peer ip address from host ip address.
You can't. The question doesn't make sense.
To get a peer address you have to have a peer, and to have a peer you have to have a connected socket, with which you can call getpeername().
Or, if you're a server, you can get it as a side-effect of accept() via the second and third arguments.

I did tried to implement arp-scan to find the connected client Ip address.
First we have to define the max device connected for my case will be 32. I manage to get following information from previous code
Interface lo : IP 127. 0. 0. 1 : MAC = 00:00:00:00:00:00
Interface enp4s0 : IP 192.168.128. 88 : MAC = f4:8e:38:ea:88:23
Interface wlp5s0 : IP 192.168. 53. 63 : MAC = b8:81:98:b7:71:90
The information that require by arp-scan is interface name and the device IP address. In order to get client ip address we have to remove the character after counting the third dot. The end result we will get is:
127.0.0.
192.168.128.
192.168.53.
the last step is to loop for max device
127.0.0.0~31
192.168.128.0~31
192.168.53.0~31
Then feed into arp-scan ping and we will get the response from client ip address. I am using this arp-scan reference.

Related

ARP Response over router

I am pretty new to networking and I have been trying to understand ARP requests. I've been using mininet and wireshark in order to test what I'm doing.
When I use mininet to generate 2 hosts (h1 and h2) and a switch, my ARP broadcast is immediately responded with an ARP reply, everything works correctly.
When I use a given router.py script that generates the following on mininet -
*** Creating network
*** Adding controller
*** Adding hosts:
h1x1 h1x2 h2x1 h2x2 h3x1 h3x2 r0
*** Adding switches:
s1 s2 s3
*** Adding links:
(h1x1, s1) (h1x2, s1) (h2x1, s2) (h2x2, s2) (h3x1, s3) (h3x2, s3) (s1, r0) (s2, r0) (s3, r0)
*** Configuring hosts
h1x1 h1x2 h2x1 h2x2 h3x1 h3x2 r0
*** Starting controller
c0
*** Starting 3 switches
s1 s2 s3 ...
*** Routing Table on Router:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 r0-eth3
172.16.0.0 0.0.0.0 255.240.0.0 U 0 0 0 r0-eth2
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 r0-eth1
// ./a.out Send <InterfaceName> <DestIP> <RouterIP> <Message>
mininet> h1x1 ./a.out Send h1x1-eth0 10.0.0.1 192.168.1.100 'This is a test'
This is how I run my command on mininet to run the ARP request.
When I try to run the ARP request using destination IP 10.0.0.1 and the router IP 192.168.1.00 my ARP request broadcasts normally, but I do not get the ARP reply, instead I get a series of ICMPv6 responses.
Here is how I am creating my ARP header
struct arp_hdr construstArpRequest(char if_name[], int sockfd, struct in_addr dst, struct ifreq if_hwaddr) {
printf("Constructing ARP request --\n");
struct arp_hdr arphdr;
arphdr.ar_hrd = htons(0x0001);
arphdr.ar_pro = htons(0x0800);
arphdr.ar_hln = 6;
arphdr.ar_pln = 4;
arphdr.ar_op = htons(0x0001);
unsigned long sip = get_ip_saddr(if_name, sockfd); // source IP
memcpy(arphdr.ar_sip, &sip, 4); // source IP
memcpy(arphdr.ar_tip, &dst.s_addr, 4); // taget IP
memset(arphdr.ar_tha, 0, 6); // taget HA
memcpy(arphdr.ar_sha, if_hwaddr.ifr_hwaddr.sa_data, 6); // source HA
return arphdr;
}
And I create my ARP request
int sockfd = -1;
if((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0){
perror("socket() failed!");
}
// connect to an internet frame
struct ifreq if_hwaddr;
memset(&if_hwaddr, 0, sizeof(struct ifreq));
strncpy(if_hwaddr.ifr_name, interfaceName, IFNAMSIZ-1);
if(ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0){
perror("SIOCGIFHWADDR");
}
struct arp_hdr arpRequest;
arpRequest = construstArpRequest(interfaceName, sockfd, router_ip, if_hwaddr);
If I need to include code about how I am actually sending the request, I can but not sure if it is necessary code. Throughout my research I have come across some answers saying that you will not get the broadcast response because you are running it over a network, it that's the case, how do you get the target MAC address?
ARP requests are for IPv4 only, and use broadcast (IPv6 does not have broadcast, and it uses NDP, not ARP), but routers do not forward broadcasts to a different network.
A source host will mask the destination address with its configured mask to determine if the destination address is on the same network. If the destination is on the same network, it will use ARP (either in the ARP table, or send a new ARP request) to determine the destination host data-link address and use that to build the data-link frame. If the destination is on a different network, the source host will use ARP (either in the ARP table, or send a new ARP request) to determine the data-link address of its configured gateway, and it will use the gateway data-link address to build the data-link frame.
You are trying to use an ARP request for a host on a different network, and that will not work. Trying to send an ARP request for a destination on a different network will get no response, and you are seeing that (you need to implement a timeout for your ARP requests, and send an error message up the network stack to the requesting process when it times out).
The IPv6 traffic you see is normal IPv6 maintenance traffic that periodically happens on a LAN where IPv6 is configured.

Printing the Source and Destination IP address from an ARP Packet

I am able to print the destination and source address from an ARP packet. But I want to print the source ip and destination ip address from the ARP request. I have searched in the and found this structure.
`struct ether_arp {
struct arphdr ea_hdr;
u_char arp_sha[6];
u_char arp_spa[4];
u_char arp_tha[6];
u_char arp_tpa[4];
};`
But when I am trying to print arp_spa I am getting something like 0:1:8:0.
Obviously this is not the source IP address.
arp_ptr = (struct ether_arp *) packet;
I feel this is wrong as some bytes need to be skipped. But I am not sure about this
Can anybody please comment.
EDIT :
arp_ptr = (struct ether_arp *) packet;
ptr = arp_ptr->arp_sha;
i = ETHER_ADDR_LEN;
printf(" source is: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
}while(--i>0);
The above is the code I am using to print either source IP or source MAC from ARP request

Linux IPv6 source address selection when interface has >1 IPv6 addresses: How to deprecate one?

In the context of IPv6 source address selection for outgoing traffic in Linux:
I have some IPv6 address(es) on the interface.
I want the kernel to pick one of those as the source IPv6 addr.
I don't want the kernel to pick this address I'm about to send it as the source address for outgoing packets.
More concretely, in this snippet I would like for the kernel to select any other IPv6 address already on this interface when dontUseAsSourceAddressForOutgoingPkts is true.
What flags will yield that effect?
If I'm using the wrong ifaddrmsg struct for IPv6 addressing, which one should I be using?
Snippet containing further context:
int
NetLnkSock::IpAdd(const std::string &ifname,
const IpAddr &ipaddr,
int prefixlen,
bool dontUseAsSourceAddressForOutgoingPkts)
ifreq ifr;
nlmsghdr *nlh;
ifaddrmsg *ifa;
nlmsgerr *nlerr;
static uint32_t msg_seq = 0;
NlSock nlsock;
LogDev::Ostream logostr;
nlsock.bind();
memset(&ifr, 0, sizeof(ifr));
if (ifname.size() > IFNAMSIZ)
throw NetLnkNameErr();
copy(ifname.begin(), ifname.end(), ifr.ifr_name);
ifr.ifr_name[ifname.end() - ifname.begin()] = '\0';
nlh = (nlmsghdr *)rcvbuf;
nlh->nlmsg_len = sizeof(nlmsghdr);
nlh->nlmsg_type = RTM_NEWADDR;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nlh->nlmsg_seq = ++msg_seq;
nlh->nlmsg_pid = 0;
ifa = (ifaddrmsg *)&nlh[1];
ifa->ifa_family = (ipaddr.is_v4()) ? AF_INET : AF_INET6;
ifa->ifa_prefixlen = prefixlen;
/*
* My question is about the behavior of the kernel
* vis a vis source address selection for outgoing traffic
* where there are multiple IP's on this interface.
* How do the flags below impact the kernel's choice
* for source address selection?
*/
ifa->ifa_flags =
(dontUseAsSourceAddressForOutgoingPkts && ipaddr.is_v6()) ?
(IFA_F_SECONDARY | IFA_F_DEPRECATED) : 0;
/*
* I would like for the kernel to select any other IPv6
* address already on this interface when
* dontUseAsSourceAddressForOutgoingPkts is true.
* Will these flags yield that effect?
*/
ifa->ifa_scope = RT_SCOPE_UNIVERSE;
ifa->ifa_index = ifr.ifr_ifindex;
nlh->nlmsg_len += sizeof(ifaddrmsg);
if (ipaddr.is_v4()) {
IpAddr ip4_bcast;
char *buf = rcvbuf + nlh->nlmsg_len;
ip4_bcast.create_netmask(prefixlen, ipaddr);
ip4_bcast.from_v4(~ip4_bcast.get_v4() | ipaddr.get_v4());
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_LOCAL,
&ipaddr.get_v4(), sizeof(in_addr_t)));
/*
* Always send the netmask and broadcast even on delete.
* Linux seems to ignore the prefixlen set in the original
* message and simply matches by ip address on deletes.
*/
buf = rcvbuf + nlh->nlmsg_len;
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_ADDRESS,
&ipaddr.get_v4(), sizeof(in_addr_t)));
buf = rcvbuf + nlh->nlmsg_len;
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_BROADCAST,
&ip4_bcast.get_v4(), sizeof(in_addr_t)));
} else { /* AF_INET6 */
char *buf = rcvbuf + nlh->nlmsg_len;
buf = rcvbuf + nlh->nlmsg_len;
if (ipaddr.domain() != RD_DEFAULT_ID) { // Hal doesn't support route domains
throw NetLnkIpAddrErr();
}
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_LOCAL,
&ipaddr.get_v6(), sizeof(in6_addr)));
buf = rcvbuf + nlh->nlmsg_len;
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_ADDRESS,
&ipaddr.get_v6(), sizeof(in6_addr)));
}
nlsock.sendNlReq(rcvbuf);
}
RFC 3484 states:
Source Address Selection
<...>
Rule 3: Avoid deprecated addresses.
The addresses SA and SB have the same scope. If one of the two
source addresses is "preferred" and one of them is "deprecated" (in
the RFC 2462 sense), then prefer the one that is "preferred."
<...>
The rtnetlink(7) man pages briefly mention a struct called ifa_cacheinfo.
This struct contains two flags of notable import: ifa_valid and ifa_prefered.
In order to mark an IPv6 address as Deprecated, set its prefered_lft to zero. Additionally, it seems customary to also set valid_lft to 0xffffffff (forever) to emphasize the explicitly deprecated nature of this IPv6 address.
/*
* You have just put a new IPv6 address on the kernel with
* net link. You don't want it chosen as the source address
* of packets leaving this interface if there's at least one
* other IPv6 address already on this interface.
*
* Mark this IPv6 address as Deprecated on this interface,
* Causing LINUX not to choose it for source address of
* packets outgoing from this interface when there exists
* another, non-deprecated IPv6 address on this interface
*/
struct ifa_cacheinfo ci;
// This address is valid forever
ci.ifa_valid = 0xffffffff;
// A prefered ttl of 0 immediately deprecates this IPv6
ci.ifa_preferred = 0;
// <Send this cacheinfo to the kernel using net link>
The rtnetlink(7) man pages just say:
ifa_flags is a flag word of IFA_F_SECONDARY for secondary address (old alias interface), IFA_F_PERMANENT for a permanent address set by the user and other undocumented flags.
Indeed, the kernel sources do not seem to document them:
/* ifa_flags */
#define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_NODAD 0x02
#define IFA_F_OPTIMISTIC 0x04
#define IFA_F_DADFAILED 0x08
#define IFA_F_HOMEADDRESS 0x10
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
#define IFA_F_PERMANENT 0x80
#define IFA_F_MANAGETEMPADDR 0x100
#define IFA_F_NOPREFIXROUTE 0x200
#define IFA_F_MCAUTOJOIN 0x400
#define IFA_F_STABLE_PRIVACY 0x800
However, the RFC 3549 "Linux Netlink as an IP Services Protocol" clarifies a bit more:
Flags: 8 bits
IFA_F_SECONDARY For secondary address (alias interface).
IFA_F_PERMANENT For a permanent address set by the user.
When this is not set, it means the address
was dynamically created (e.g., by stateless
autoconfiguration).
IFA_F_DEPRECATED Defines deprecated (IPV4) address.
IFA_F_TENTATIVE Defines tentative (IPV4) address (duplicate
address detection is still in progress).
So it seems the two flags are not related: one marks an interface address as being secondary (temporary); while the other defines a IPv4 address ("deprecated").
If you need to see exactly what are the implications of each flag, you can take a look at references for the symbol in the source code, for instance at IFA_F_SECONDARY and IFA_F_DEPRECATED.

Get the size of ARP packet

I am currently decomposing a data packet into several headers.
Here's my current code :
void analyse(struct pcap_pkthdr *header, const unsigned char *packet, int verbose) {
// Define headers and payload
const struct ether_header *ethernet = NULL;
const struct ether_arp *arp = NULL;
const struct ip *ip = NULL;
const struct tcphdr *tcp = NULL;
const char *payload = NULL;
/* Ethernet header is the first data block of packet **/
ethernet = ( struct ether_header* ) packet;
// ARP packet following
if( ntohs( ethernet->ether_type ) == ETHERTYPE_ARP ) {
arp = ( struct ether_arp* ) ( packet + ETH_HLEN );
// If the operation performed by the sender is a reply, we increment the ARP Response Counter
if( ntohs(arp->ea_hdr.ar_op ) == 2 ) {
arpResponsesCounter++;
}
} else { // IP packet following
ip = ( struct ip* ) ( packet + ETH_HLEN );
}
// ARP header and IP header don't have the same size
if( arp == NULL ) {
u_int shift_size = (ip->ip_hl)*4;
} else {
}
}
According to http://unix.superglobalmegacorp.com/BSD4.4/newsrc/netinet/ip.h.html and http://unix.superglobalmegacorp.com/Net2/newsrc/netinet/if_ether.h.html , the size of an IP header is given by (ip->ip_hl)*4; but I can't figure out how to get the size of an ARP header.
I need it to define properly the TCP header pointer.
Thanks
I think you are confused. The ARP packet is the ARP header. ARP is a protocol unto itself, and it doesn't contain other protocols as payloads in its packets the way IP does. It is properly a Link-Layer protocol in the way ICMP is a Network-Layer protocol. Both are top-layer protocols, and neither carries other protocols.
You can determine the size of an ARP packet on a network if you know the size of the layer-2 and layer-3 addresses for the network (48 bits for ethernet and 32 bits for IPv4).
Hardware Type is two octets
Protocol Type is two octets
Hardware Address Length is one octet
Protocol Address Length is one octet
Operation is two octets
Sender Hardware Address is Hardware Address Length octets
Sender Protocol Address is Protocol Address Length octets
Destination Hardware Address is Hardware Address Length octets
Destination Protocol Address is Protocol Address Length octets
Basically, you have eight octets, plus two times the Hardware Address Length, plus two times the Protocol Address Length.
For IPv4 on ethernet, this means ( 8 + ( 2 * 6 ) + ( 2 * 4 ) ) = 28.

Neighbor solicitation sent instead of ICMP6 echo resquest

I'm trying to send an ICMPV6 echo request. Bellow my code:
struct icmp6_hdr icmp6;
int sock;
struct icmp6_filter filterv6;
struct ifreq ifr;
sock = socket(AF_INET6, SOCK_RAW,IPPROTO_ICMPV6);
ICMP6_FILTER_SETBLOCKALL(&filterv6);
ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filterv6);
ICMP6_FILTER_SETPASS(ND_REDIRECT, &filterv6);
setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filterv6, sizeof (filterv6));
...
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr);
...
icmp6.icmp6_type = ICMP6_ECHO_REQUEST;
icmp6.icmp6_code = 0;
icmp6.icmp6_cksum = 0;
icmp6.icmp6_id = id;
icmp6.icmp6_seq = 100;
if( (sendto(sock, &icmp6, sizeof(struct icmp6_hdr), 0, (struct sockaddr *)dest, socklen)) != sizeof(struct icmp6_hdr))
However, for an unknown reason, the sent packet is an NDS:
[root#jingo ~]# tcpdump -v -i any -s0 | grep icmp6
tcpdump: WARNING: Promiscuous mode not supported on the "any" device
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
11:57:08.397368 IP6 (hlim 255, next-header: ICMPv6 (58), length: 32) 2001:db8:0:85a3::ac1f:8003 > ff02::1:ff1f:8009: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has 2001:db8:0:85a3::ac1f:8009
11:57:09.397331 IP6 (hlim 64, next-header: ICMPv6 (58), length: 112) 2001:db8:0:85a3::ac1f:8003 > 2001:db8:0:85a3::ac1f:8003: [icmp6 sum ok] ICMP6, destination unreachable, length 112, unreachable address 2001:db8:0:85a3::ac1f:8009
I'm using 2.6.18-308.el5PAE kernel , Red Hat Enterprise Linux Server release 5.1 (Tikanga).
This is normal behavior.
Since you can't send IP traffic until you have the correct MAC address to direct packets to, something has to find that MAC address. In IPv4, you would have seen an ARP packet. NDP (neighbor discovery protocol) replaced ARP in IPv6, which is why you're seeing NDP traffic.
The real problem here is that the destination host is not reachable. It may be down, or the router may not know how to reach it. Your router might be configured incorrectly, but that seems unlikely.
Try pinging a host that is up, and you will see the NDP traffic followed by your ICMP echo request.

Resources