How to find the scope_id for an IPv6 socket - c

I use a IPv6 UDP socket connection in my code. The execution fails, because the device does not exist.
strerror(errno)
responded with
No such device
I use a link local address.
Server
fe80::213:afff:fe94:d75
Client
fe80::f2d5:bfff:fe10:f1b1
I got the scope_id by ifconfig:
bt0: flags=4177<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1280
inet6 fe80::f2d5:bfff:fe10:f1b1 prefixlen 64 scopeid 0x20<link>
unspec F0-D5-BF-FF-FE-10-F1-B1-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 3 bytes 84 (84.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 11 bytes 370 (370.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Since another interface has the same scope_id, I guess the scope_id means here the IPv6 scope. 0x20 = link_local.
enp0s31f6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.4 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::fb58:43b9:10fa:101 prefixlen 64 scopeid 0x20<link>
inet6 2a02:8109:b6bf:ca24:ae7f:b967:932e:b2f4 prefixlen 64 scopeid 0x0<global>
inet6 2a02:8109:b6bf:ca24:51f:6c37:66c4:5282 prefixlen 64 scopeid 0x0<global>
ether c8:5b:76:98:55:bf txqueuelen 1000 (Ethernet)
RX packets 16413820 bytes 20299047086 (20.2 GB)
RX errors 18 dropped 0 overruns 0 frame 16
TX packets 6110718 bytes 714537636 (714.5 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 16 memory 0xf1200000-f1220000
So, I used this scope_id in my code:
#define CLIENT_ADDRESS { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0xd5, 0xbf, 0xff, 0xfe, 0x10, 0xf1, 0xb1 };
struct sockaddr_in6 client_addr;
unsigned int client_addr_len = sizeof(client_addr);
memset(&client_addr, 0, client_addr_len);
client_addr.sin6_family = AF_INET6;
client_addr.sin6_port = htons(PORT);
client_addr.sin6_scope_id = 0x20;
uint8_t address[16] = CLIENT_ADDRESS;
memcpy(&client_addr.sin6_addr, address, 16);
This is not the correct interface.
So my question: Where can I find the correct scope_id for my interface?
Is there some linux tool to get it?

Maybe if_nametoindex() is what you are looking for:
client_addr.sin6_scope_id = if_nametoindex("tun0");
More information of if_nametoindex in man page.

Okay, I got it. The scope_id in sockaddr_in6 is the interface ID. You can find the interface ID with
ip link show

Related

Filter Arp-Replies

I'am writing an network library in C from scratch. I already implemented the Ethernet protocol and now I want to get ARP working.
Sending Requests/Replies works fine but receiving isn't working well.
When I send an send an Request and wait for the Reply after it, recvfrom() just takes the first incoming ARP packet. But I want to get the Reply from the host replying to my Request.
I can't just receive packets until the correct one arrives because the library should support socket timeouts. (set with setsockopt())
The socket is created like this:
int sfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))
Output of my test program:
Sending ARP-Request ...
0o0o0o0 ARP-FRAME DUMP 0o0o0o0
HwType: 256 (0x7ab74e358670)
PrType: 8 (0x7ab74e358672)
HwALen: 6 (0x7ab74e358674)
PrALen: 4 (0x7ab74e358675)
ArpOP : 256 (0x7ab74e358676)
Sha : 84:4b:10:14:a0:04 (0x7ab74e358678)
Spa : 192.168.12.1 (0x7ab74e35867e)
Tha : 00:00:00:00:00:00 (0x7ab74e358682)
Tpa : 192.168.0.3 (0x7ab74e358688)
Receiving ARP-Reply ...
0o0o0o0 ARP-FRAME DUMP 0o0o0o0
HwType: 256 (0x7ab74e358670)
PrType: 8 (0x7ab74e358672)
HwALen: 6 (0x7ab74e358674)
PrALen: 4 (0x7ab74e358675)
ArpOP : 512 (0x7ab74e358676)
Sha : 10:00:00:00:00:01 (0x7ab74e358678)
Spa : 192.168.12.78 (0x7ab74e35867e)
Tha : 84:4b:10:14:a0:04 (0x7ab74e358682)
Tpa : 192.168.12.1 (0x7ab74e358688)
Is it possible to filter incoming ARP packets/how to do it?
Thanks in advance.
--- EDIT ---
I played around with the BPF and it worked fine for filtering out ARP packets.
It wrote this filter
ld [28]
jne #0x4e0ca8c0, drop
ret #-1
drop: ret #0
to filter the incoming ARP replies.
It should load the source IP from the packet and compare it with the one defined in the code. 0x4e0ca8c0 is the valid IP addr. of the host whose reply I want. tcpdump shows the incoming reply but my program freezes (Waits forever).
I used the BPF like this:
struct sock_fprog prog;
struct sock_filter filter[4] =\
{{ 0x20, 0, 0, 0x0000001c },
{ 0x15, 0, 1, 0x4e0ca8c0 },
{ 0x06, 0, 0, 0xffffffff },
{ 0x06, 0, 0, 0000000000 }};
prog.len = 4;
prog.filter = filter;
if(setsockopt(sfd, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) ==\
-1) {
fprintf(stderr, "ERROR enabling bpf: setsockopt(): %s\n",\
strerror(errno));
goto ... (error handler);
}
/* Receive incoming ARP reply */
I hope I haven't made any stupid/obvious mistakes.
Thanks in advance!
-- LAST EDIT --
The IP addr. must be in NBO.
So with the correct BPF:
struct sock_filter filter[4] =\
{{ 0x20, 0, 0, 0x0000001c },
{ 0x15, 0, 1, 0xc0a80c4e },
{ 0x06, 0, 0, 0xffffffff },
{ 0x06, 0, 0, 0000000000 }};
... only replies from 192.168.12.78 (0xc0a80c4e) are accepted/received.
Huge thanks to Ctx!
You can use a (properly configured) Berkeley Packet Filter (BPF) for it.
For this, you have to write a (small) BPF-filter, which exactly matches the reply you are looking for.
#include <linux/filter.h>
struct sock_filter filter[NR_INSTRUCTIONS];
filter[0].code = ...;
filter[0].k = ...;
filter[0].jt = ...;
filter[0].jf = ...;
filter[1].code = ...;
...
The "language" is very basic and is described here
Then put the instructions together into a BPF program:
struct sock_fprog prog;
prog.len = NR_INSTRUCTIONS;
prog.filter = filter;
Finally, you can attach the filter to your socket:
setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog));
If you configured your filter correctly, you will only receive the matching arp replies on your socket from now on.
For the next request/reply you have to reconfigure the filter to match the new parameters (SO_DETACH_FILTER followed by SO_ATTACH_FILTER with the new program).
For ARP packets it is especially easy to construct a filter, since the offsets of the fields in the packet are fixed.

Why does the read with lsusb fails?

I need to read the response from a control unit of a motor. After the write of a command beginning with ?, the motor unit should respond with some text. I.e. on ?MSG it should report its status. But when I try to read the status the unit sends nothing and the request ends with a timeout.
The code is pretty straightforward and uses libusb. The program detaches all active drivers from the device, attaches itself to the device, transfers the command ?MSG and waits for response. After that it detaches and ends.
Why there is no response? Is there any error in code or is it an issue of the motor unit? I am sure that commands are sent and received by the unit as the motor moves, for example, on PSET1=4000
#include <assert.h>
#include <string.h>
#define VENDOR_ID 0x0483
#define PRODUCT_ID 0x5740
#define BULK_EP_IN 0x03
#define BULK_EP_OUT 0x81 // From computer to control unit
#define INTERFACE_IN 0
#define INTERFACE_OUT 1
#define BUF_SIZE 64
int main()
{
libusb_context *ctx;
libusb_device_handle *dev_handle;
int r = 0;
int actual, length, received;
char cmd[] = "?MSG\r\n";
char buffer[BUF_SIZE];
length = strlen(cmd);
r = libusb_init(&ctx);
assert(r == 0);
/* Set verbosity level to 3, as suggested in the documentation */
libusb_set_debug(ctx, 3);
/* Get device handle */
dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID);
assert(dev_handle != NULL);
/* Find out if kernel driver is attached on IN iface */
if(libusb_kernel_driver_active(dev_handle, INTERFACE_IN) == 1) {
printf("Kernel Driver Active\n");
assert(libusb_detach_kernel_driver(dev_handle, INTERFACE_IN) == 0);
printf("Kernel Driver Detached!\n");
}
if(libusb_kernel_driver_active(dev_handle, INTERFACE_OUT) == 1) {
printf("Kernel Driver Active\n");
assert(libusb_detach_kernel_driver(dev_handle, INTERFACE_OUT) == 0);
printf("Kernel Driver Detached!\n");
}
/* Claim IN interface of device */
r = libusb_claim_interface(dev_handle, INTERFACE_IN);
assert(r >= 0);
/* claim OUT interface of device */
r = libusb_claim_interface(dev_handle, INTERFACE_OUT);
assert(r >= 0);
/* Transfer commands */
r = libusb_bulk_transfer(dev_handle, BULK_EP_IN, (unsigned char *)cmd, length, &actual, 0);
assert(r == 0 && actual > 0 && actual == length);
printf("Written %s\n",cmd);
/* Now read response */
if (cmd[0] == '?') {
char buffer[BUF_SIZE] = "";
int received = 0;
do {
int i;
r = libusb_bulk_transfer(dev_handle, BULK_EP_OUT, (unsigned char *)buffer, BUF_SIZE, &received, 1000);
if(r == LIBUSB_ERROR_TIMEOUT) {
printf("Timeout\n");
} else {
assert(r == 0);
}
for(i = 0; i<BUF_SIZE;i++)
printf("%c",buffer[i]);
} while (received != 0);
}
/* Release devices */
r = libusb_release_interface(dev_handle, INTERFACE_IN);
assert(r == 0);
r = libusb_release_interface(dev_handle, INTERFACE_OUT);
assert(r == 0);
/* Clean */
libusb_close(dev_handle);
libusb_exit(ctx);
}
Here is a description of the device with sudo lsusb --verbose in case it's important:
Bus 003 Device 003: ID 0483:5740 STMicroelectronics STM32F407
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0483 STMicroelectronics
idProduct 0x5740 STM32F407
bcdDevice 1.00
iManufacturer 1 STMicroelectronics
iProduct 2 STR75x Virtual COM Port
iSerial 3 Demo 1.000
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 67
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
iInterface 0
CDC Header:
bcdCDC 1.10
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 255
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Status: 0x0001
Self Powered
You can communicate with the device by the RS-232 protocol, because it provides a virtual COM port which is a CDC ACM class. The kernel driver is cdc_acm.
iManufacturer 1 STMicroelectronics
iProduct 2 STR75x Virtual COM Port
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
iInterface 0
CDC Header:
bcdCDC 1.10
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
So you can communicate with the device by sending RS-232 commands to /dev/ttyACMx (or /dev/ttyUSBx) (replace x with the number on your system)
To check this you can use a terminal program like PuTTY,... 5 Linux / Unix Commands For Connecting To The Serial Console. You have to figure out the correct COM port settings (baud rate, parity, start/stop bits, etc.)
There are several RS-232 libraries, see C: cross-platform RS-232 serial library?
Check the dmesg output after plugin in the device to see which driver is used.

Sending don't fragment UDP packets at the server and receiving fragmented packets at the client

I've created a program in C that sends data with UDP packets.
Socket is made don't fragment using
int optval = IP_PMTUDISC_DO;
if(setsockopt(sd,IPPROTO_IP,IP_MTU_DISCOVER,&optval,sizeof(int))!=0)
{
perror("setsocketopt()");
return 0;
}
Checking with TSHARK at the server (debian 8 KVM virtualizied), for all packets don't fragment has been set:
But at the client, large packets receiving fragmented!!
Then I figured something more wired. The IPv4 ID field has been set to 0!
I thought it might be because of the don't fragment effect (because no packet is going to be fragmented).
Then I started Openvpn program and sniffed its packets at the server but the packets had IPv4 ID != 0 while don't fragment was set.
Do you guys have any idea that why is this happening to me?!
Edit: Here is another sample of a large packet at server copy and pasted from tshark result.
Frame 1049: 1514 bytes on wire (12112 bits), 1514 bytes captured (12112 bits) on interface 0
Ethernet II, Src: server_mac, Dst: gateway_mac
Internet Protocol Version 4, Src: server_ip, Dst: client_ip
Version: 4
Header Length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
Total Length: 1500
Identification: 0x0000 (0)
Flags: 0x02 (Don't Fragment)
0... .... = Reserved bit: Not set
.1.. .... = Don't fragment: Set
..0. .... = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: UDP (17)
Header checksum: 0xa52d [validation disabled]
[Good: False]
[Bad: False]
Source: server_ip
Destination: client_ip
[Source GeoIP: Unknown]
[Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: 7554 (7554), Dst Port: 45376 (45376)
Data (1472 bytes)
Like you see, don't fragment has been set, while all packets larger than PMTU are receiving fragmented to client side.
This is a packet trace example of openvpn on the same server. like you see it at least has IPv4 ID calculated!
Frame 3749: 1455 bytes on wire (11640 bits), 1455 bytes captured (11640 bits) on interface 0
Ethernet II, Src: SERVER_MAC, Dst: GATEWAY_MAC
Internet Protocol Version 4, Src: SERVER_IP, Dst: CLIENT_IP
Version: 4
Header Length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
Total Length: 1441
Identification: 0xcc96 (52374)
Flags: 0x02 (Don't Fragment)
0... .... = Reserved bit: Not set
.1.. .... = Don't fragment: Set
..0. .... = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: UDP (17)
Header checksum: 0xe252 [validation disabled]
[Good: False]
[Bad: False]
Source: SERVER_IP
Destination: CLIENT_IP
[Source GeoIP: Unknown]
[Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: 19234 (19234), Dst Port: 46921 (46921)
Data (1413 bytes)

Why can't I capture raw packet even though tcpdump can?

I'm trying to capture port-mirroring packets using raw socket (skipped error checking to show only main code):
int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
int size = recvfrom(sock, buf, 65536, 0, &saddr, &saddr_size);
struct iphdr* iph = (struct iphdr*)(buf + sizeof(struct ethhdr));
if (iph->protocol != 6 || iph->saddr != inet_addr("192.168.12.48")) return;
printf("got it\n");
Although tcpdump can capture the packets, my program can't. Here's a dump of a packet:
22:19:42.140498 IP (tos 0x0, ttl 54, id 42987, offset 0, flags [DF], proto TCP (6), length 52)
192.168.12.48.33011 > 172.16.103.12.57102: Flags [.], cksum 0xf4ef (correct), ack 7, win 186, options [nop,nop,TS val 1950796524 ecr 3768292988], length 0
0x0000: 4500 0034 a7eb 4000 3606 bce3 c0a8 0c30 E..4..#.6......0
0x0010: ac10 670c 80f3 df0e 983d f043 d1c7 3087 ..g......=.C..0.
0x0020: 8010 00ba f4ef 0000 0101 080a 7446 caec ............tF..
0x0030: e09b 967c ...|
I'm using CentOS 6.5 kernel 2.6.32-431.29.2.el6.x86_64. I already disabled firewall and set rp_filter to 0. Does anyone know how to capture such packets in C?

Why does my pc send more than 1514 byte packet in one go

I wrote a program to send 1460 byte data using TCP client and server continuously. My system interface MTU is 1500.
Here is my program of client
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
setsockopt(sockfd,SOL_TCP,TCP_NODELAY,&one,sizeof(one));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9998);
serv_addr.sin_addr.s_addr = inet_addr("10.10.12.1");
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
while(1)
{
write(sockfd, send_buff, 1448) ;
}
In wireshark initial 15 to 30 packets are showing that 1514 byte of packet is going but afterwards showing as below
wireshark output of some packet
No. Time Source Destination Protocol Length Info
16 0.000000 10.10.12.2 10.10.12.1 TCP 5858 53649 > distinct32 [ACK] Seq=3086892290 Ack=250285353 Win=14608 Len=5792 TSval=23114307 TSecr=23833274
Frame 16: 5858 bytes on wire (46864 bits), 5858 bytes captured (46864 bits)
Ethernet II, Src: 6c:3b:e5:14:9a:a2 (6c:3b:e5:14:9a:a2), Dst: Ibm_b5:86:85 (00:1a:64:b5:86:85)
Internet Protocol Version 4, Src: 10.10.12.2 (10.10.12.2), Dst: 10.10.12.1 (10.10.12.1)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
Total Length: 5844
Identification: 0x8480 (33920)
Flags: 0x00
Fragment offset: 0
Time to live: 64
Protocol: TCP (6)
Header checksum: 0xb38d [correct]
Source: 10.10.12.2 (10.10.12.2)
Destination: 10.10.12.1 (10.10.12.1)
Transmission Control Protocol, Src Port: 53649 (53649), Dst Port: distinct32 (9998), Seq: 3086892290, Ack: 250285353, Len: 5792
Source port: 53649 (53649)
Destination port: distinct32 (9998)
[Stream index: 0]
Sequence number: 3086892290
[Next sequence number: 3086898082]
Acknowledgement number: 250285353
Header length: 32 bytes
Flags: 0x010 (ACK)
Window size value: 913
[Calculated window size: 14608]
[Window size scaling factor: 16]
Checksum: 0x42dd [validation disabled]
Options: (12 bytes)
No-Operation (NOP)
No-Operation (NOP)
Timestamps: TSval 23114307, TSecr 23833274
Data (5792 bytes)
On wireshark it is showing that more than 5792, 7000, 65535 byte of packet are going.
But i am sending 1514 byte of packet in one go. on other side i am receiving 1514 byte of packets only due to network mtu.
So my question is
why this much of huge packets are going ?
I tried without NODELAY option also but it is not working.
Is there any solution to send particular packet size (such as 1514 byte) can be send, no jumbo frames ?
I update my tcp_rmem and tcp_wmem also for tcp sending buffer and receiving buffer also. But did not found any solution.
TCP, by design, bundles up multiple write() calls into larger packets. Also, TCP coalesces packets by default according to Nagle's Algorithm.
If you want more control over the actual size of network packets, use UDP.
These are "jumbo frames", and they're faster than traditional frame sizes because they don't load up a CPU as much.
Consider yourself fortunate that you're getting them without futzing around with your IP stack's settings.
I searched a lot and found that, we need to change some parameter on interface.
On my interface eth0 default option are
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
now using ethtool we need to off some sending side segementation offload.
For that
sudo ethtool -K eth0 tso off gso off
using this
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: off
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
After this your interface will send packets whatever you want to send.

Resources