Linux netlink mutlicast routing updates - linux

My application should get netlink multicast route updates from kernel.
I did some research and found mutlicast uses different family:RTNL_FAMILY_IPMR
and group is RTMGRP_IPV4_MROUTE.
However if I use:
sfd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
snl.nl_groups |= RTMGRP_IPV4_MROUTE
I dont get any updates.
But
sfd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
snl.nl_family = RTNL_FAMILY_IPMR;
snl.nl_groups |= RTMGRP_IPV4_MROUTE;
This give bind error", bind: Invalid argument
sfd = socket (RTNL_FAMILY_IPMR, SOCK_RAW, NETLINK_ROUTE);
This give "Address family not supported by protocol" error
I'm not sure how to get updates from kernel for mutlicast routes.

copy-paste from earlier project I have:
struct sockaddr_nl naddr;
netlinkfd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
naddr.nl_family = AF_NETLINK;
naddr.nl_groups = (1 << (RTNLGRP_LINK - 1)) |
(1 << (RTNLGRP_IPV4_ROUTE - 1)) |
(1 << (RTNLGRP_IPV6_ROUTE - 1)) |
(1 << (RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (RTNLGRP_IPV6_IFADDR -1 ));
if (bind (netlinkfd, (struct sockaddr *)&naddr, sizeof (naddr)))
{
error_foo();
return;
}
This one works for me receiving link, ip and routing table in general. (pushing me all the changes from this point of - if I want to receive the current status, I need to request them aswell). Try to have both ROUTE and MROUTE since you want multicast routing tables, but they might be merged into the normal routing table

Related

EADDRNOTAVAIL even after using IP_FREEBIND?

I was under the impression that under Linux you could bind to a non-local address as long as you set the IP_FREEBIND socket option, but that's not the behavior I'm seeing:
$ sudo strace -e 'trace=%network' ...
...
socket(AF_INET, SOCK_RAW, IPPROTO_UDP) = 5
setsockopt(5, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(5, SOL_SOCKET, SO_NO_CHECK, [1], 4) = 0
setsockopt(5, SOL_IP, IP_HDRINCL, [1], 4) = 0
setsockopt(5, SOL_IP, IP_FREEBIND, [1], 4) = 0
bind(5, {sa_family=AF_INET, sin_port=htons(abcd), sin_addr=inet_addr("w.x.y.z")}, 16) = -1 EADDRNOTAVAIL (Cannot assign requested address)
...
I also set the ip_nonlocal_bind setting, just to be certain, and I get the same results.
$ sysctl net.ipv4.ip_nonlocal_bind
net.ipv4.ip_nonlocal_bind = 1
Unfortunately, it seems that it is not possible to bind a raw IP socket to a non-local, non-broadcast and non-multicast address, regardless of IP_FREEBIND. Since I see inet_addr("w.x.y.z") in your strace output, I assume that this is exactly what you're trying to do and w.x.y.z is a non-local unicast address, thus your bind syscall fails.
This seems in accordance with man 7 raw:
A raw socket can be bound to a specific local address using the
bind(2) call. If it isn't bound, all packets with the specified
IP protocol are received. In addition, a raw socket can be bound
to a specific network device using SO_BINDTODEVICE; see socket(7).
Indeed, looking at the kernel source code, in raw_bind() we can see the following check:
ret = -EADDRNOTAVAIL;
if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
goto out;
Also, note that .sin_port must be 0. The .sin_port field for raw sockets is used to select a sending/receiving IP protocol (not a port, since we are at level 3 and ports do not exist). As the manual states, from Linux 2.2 onwards you cannot select a sending protocol through .sin_port anymore, the sending protocol is the one set when creating the socket.

Reduce TCP maximum segment size (MSS) in Linux on a socket

In a special application in which our server needs to update firmware of low-on-resource sensor/tracking devices we encountered a problem in which sometimes data is lost in the
remote devices (clients) receiving packets of the new firmware. The connection is TCP/IP over
GPRS network. The devices use SIM900 GSM chip as a network interface.
The problems possibly come because of the device receiving too much data. We tried reducing the
traffic by sending packages more rarely but sometimes the error still occured.
We contacted the local retailer of the SIM900 chip who is also responsible for giving technical support and possibly contacting the chinese manufacturer (simcom) of the chip. They said that at first we should try to reduce the TCP MSS (Maximum Segment Size) of our connection.
In our server I did the following:
static int
create_master_socket(unsigned short master_port) {
static struct sockaddr_in master_address;
int master_socket = socket(AF_INET,SOCK_STREAM,0);
if(!master_socket) {
perror("socket");
throw runtime_error("Failed to create master socket.");
}
int tr=1;
if(setsockopt(master_socket,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int))==-1) {
perror("setsockopt");
throw runtime_error("Failed to set SO_REUSEADDR on master socket");
}
master_address.sin_family = AF_INET;
master_address.sin_addr.s_addr = INADDR_ANY;
master_address.sin_port = htons(master_port);
uint16_t tcp_maxseg;
socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
if(getsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len)) {
log_error << "Failed to get TCP_MAXSEG for master socket. Reason: " << errno;
perror("getsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
tcp_maxseg = 256;
if(setsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, tcp_maxseg_len)) {
log_error << "Failed to set TCP_MAXSEG for master socket. Reason: " << errno;
perror("setsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
if(getsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len)) {
log_error << "Failed to get TCP_MAXSEG for master socket. Reason: " << errno;
perror("getsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
if(bind(master_socket, (struct sockaddr*)&master_address,
sizeof(master_address))) {
perror("bind");
close(master_socket);
throw runtime_error("Failed to bind master_socket to port");
}
return master_socket;
}
Running the above code results in:
I0807 ... main.cpp:267] TCP_MAXSEG: 536
E0807 ... main.cpp:271] Failed to set TCP_MAXSEG for master socket. Reason: 22 setsockopt: Invalid argument
I0807 ... main.cpp:280] TCP_MAXSEG: 536
As you may see, the problem in the second line of the output: setsockopt returns "Invalid argument".
Why does this happen? I read about some constraints in setting TCP_MAXSEG but I did not encounter any report on such a behaviour as this.
Thanks,
Dennis
In addition to xaxxon's answer, just wanted to note my experience with trying to force my Linux to send only maximum TCP segments of a certain size (lower than what they normally are):
The easiest way I found to do so, was to use iptables:
sudo iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN --destination 1.1.1.1 -j TCPMSS --set-mss 200
This overwrites the remote incoming SYN/ACK packet on an outbound connection, and forces the MSS to a specific value.
Note1: You do not see this in wireshark, since wireshark capture before this happens.
Note 2: Iptables does not allow you to -increase- the MSS, just lower it
Alternatively, I also tried setting the socket option TCP_MAXSEG, like dennis had done. After taking the fix from xaxxon, this also worked.
Note: You should read the MSS value after the connection has been set up. Otherwise it returns the default value, which put me (and dennis) on the wrong track.
Now finally, I also ran into a number of other things:
I ran into TCP-offloading issues, where despite my MSS being set correctly, the frames being sent were still shown by wireshark as too big. You can disable this feature by : sudo ethtool -K eth0 tx off sg off tso off. This took me a long time to figure out.
TCP has lots of fancy things like MTU path discovery, which actually try to dynamically increase the MSS. Fun and cool, but confusing obviously. I did not have issues with it though in my tests
Hope this helps someone trying to do the same thing one day.
Unless otherwise noted, optval is a pointer to an int.
but you're using a u_int16. I don't see anything saying that this parameter isn't an int.
edit: Yeah, here is the source code and you can see:
637 if (optlen < sizeof(int))
638 return -EINVAL;

directions about customized Layer 2 implementation in linux

I have some machines running on the same network. One node is the control node which distributes traffic coming to it to the other nodes. The thing is that I want to have a custom protocol header between MAC header and IP(or whatever) payload incoming to the control node.
Control node receives this any packet like this:
------------------------------------------------
| Layer 2 | IP(or whatever protocol) | Payload |
------------------------------------------------
This packet should be distributed like this to other nodes
----------------------------------------------------------------
| Layer 2 | Custom Header | IP(or whatever protocol) | Payload |
----------------------------------------------------------------
I want some directions to do such a thing, Is there any current solution which I can use and I have to hack kernel for it from the scratch. A similar approach is to use L2TP but that runs over IP layer so I dont want that.
I also want this communication to be appeared as a seperate interface in linux like tun0 apart from physical eth0 interface.
Any help or ideas would be highly appreciated.
I dont know in what stack-exchange website this question belongs to so directions to correct website are also appreciated.
Your case is very similar to VLAN, where VLAN header also sits between L2 header and IP header. You can take a look at VLAN code, especially net/8021q/vlan_dev.c.
The key here is you need to construct your own L2 header, so you need to register your own header_ops like what VLAN does:
static const struct header_ops vlan_header_ops = {
.create = vlan_dev_hard_header,
.rebuild = vlan_dev_rebuild_header,
.parse = eth_header_parse,
};
and register it during initialization:
dev->header_ops = &vlan_header_ops;
dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
The ->create() function pointer here is used to create the custom header:
static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
const void *daddr, const void *saddr,
unsigned int len)
{
struct vlan_hdr *vhdr;
unsigned int vhdrlen = 0;
u16 vlan_tci = 0;
int rc;
if (!(vlan_dev_priv(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
vlan_tci = vlan_dev_priv(dev)->vlan_id;
vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
vhdr->h_vlan_TCI = htons(vlan_tci);
/*
* Set the protocol type. For a packet of type ETH_P_802_3/2 we
* put the length in here instead.
*/
if (type != ETH_P_802_3 && type != ETH_P_802_2)
vhdr->h_vlan_encapsulated_proto = htons(type);
else
vhdr->h_vlan_encapsulated_proto = htons(len);
skb->protocol = htons(ETH_P_8021Q);
type = ETH_P_8021Q;
vhdrlen = VLAN_HLEN;
}
/* Before delegating work to the lower layer, enter our MAC-address */
if (saddr == NULL)
saddr = dev->dev_addr;
/* Now make the underlying real hard header */
dev = vlan_dev_priv(dev)->real_dev;
rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
if (rc > 0)
rc += vhdrlen;
return rc;
}

Crafting an ICMP packet inside a Linux kernel Module

I'm tring to experiment with the ICMP protocol and have created a kernel-module for linux that analyses ICMP packet ( Processes the packet only if if the ICMP code field is a magic number ) . Now to test this module , i have to create a an ICMP packet and send it to the host where this analysing module is running . In fact it would be nice if i could implement it the kernel itself (as a module ) . I am looking for something like a packetcrafter in kernel , I googled it found a lot of articles explaining the lifetime of a packet , rather than tutorials of creating it . User space packetcrafters would be my last resort, that too those which are highly flexible like where i'll be able to set ICMP code etc . And I'm not wary of kernel panics :-) !!!!! Any packet crafting ideas are welcome .
Sir, I strongly advice you against using the kernel module to build ICMP packets.
You can use user-space raw-sockets to craft ICMP packets, even build the IP-header itself byte by byte.
So you can get as flexible as it can get using that.
Please, take a look at this
ip = (struct iphdr*) packet;
icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
/*
* here the ip packet is set up except checksum
*/
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
ip->id = htons(random());
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
ip->saddr = inet_addr(src_addr);
ip->daddr = inet_addr(dst_addr);
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
{
perror("socket");
exit(EXIT_FAILURE);
}
/*
* IP_HDRINCL must be set on the socket so that
* the kernel does not attempt to automatically add
* a default ip header to the packet
*/
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
/*
* here the icmp packet is created
* also the ip checksum is generated
*/
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->un.echo.id = 0;
icmp->un.echo.sequence = 0;
icmp->checksum = 0;
icmp-> checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));
If this part of code looks flexible enough, then read about raw sockets :D maybe they're the easiest and safest answer to your need.
Please check the following links for further info
http://courses.cs.vt.edu/~cs4254/fall04/slides/raw_6.pdf
http://www.cs.binghamton.edu/~steflik/cs455/rawip.txt
http://cboard.cprogramming.com/networking-device-communication/107801-linux-raw-socket-programming.html a very nice topic, pretty useful imo
You can try libcrafter for packet crafting on user space. Is very easy to use! The library is able to craft or decode packets of most common networks protocols, send them on the wire, capture them and match requests and replies.
For example, the next code craft and send an ICMP packet:
string MyIP = GetMyIP("eth0");
/* Create an IP header */
IP ip_header;
/* Set the Source and Destination IP address */
ip_header.SetSourceIP(MyIP);
ip_header.SetDestinationIP("1.2.3.4");
/* Create an ICMP header */
ICMP icmp_header;
icmp_header.SetType(ICMP::EchoRequest);
icmp_header.SetIdentifier(RNG16());
/* Create a packet... */
Packet packet = ip_header / icmp_header;
packet.Send();
Why you want to craft an ICMP packet on kernel-space? Just for fun? :-p
Linux kernel includes a packet generator tool pktgen for testing the network with pre-configured packets. Source code for this module resides in net/core/pktgen.c

How to implement ACTION (move/rename, set permissions) operation in J2ME Bluetooth OBEX?

Bluetooth FTP specification says I need to use ACTION operation, here's a page
But the ClentSession provides only GET and PUT operations, and nothing mentioned in javadocs.
here's how the create file operation looks, it's pretty easy
public void create() throws IOException {
HeaderSet hs = cs.createHeaderSet();
hs.setHeader(HeaderSet.NAME, file);
op = cs.put(hs);
OutputStream os = op.openOutputStream();
os.close();
op.close();
}
Question 1: How do I implement ACTION operation with custom headers to perform move/rename and set permissions? It should be possible without JSR82 OBEX API. Please help me to do this.
Question 2:
Did I understand how to set permissions?
According to OBEX_Errata Compiled For 1.3.pdf (thanks alanjmcf!)
So, to set read-only, I should do the following:
int a = 0;
//byte 0 //zero
//byte 1 //user
//byte 2 //group
//byte 3 //other
//set read for user
a |= (1 << 7); //8th bit - byte 1, bit 0 -> set to 1
// a = 10000000
//for group
a |= (1 << 15); //16th bit - byte 2, bit 0 -> set to 1
// a = 1000000010000000
//for other
a |= (1 << 23); //24th bit - byte 3, bit 0 -> set to 1
// a = 100000001000000010000000
//or simply
private static final int READ = 8421504 //1000,0000,1000,0000,1000,0000
int value = 0 | READ;
//========== calculate write constant =========
a = 0;
a |= (1 << 8); //write user
a |= (1 << 16); //write group
a |= (1 << 24); //write other
// a = 1000000010000000100000000
private static final int WRITE = 16843008 // 1,0000,0001,0000,0001,0000,0000
//========= calculate delete constant ==========
a = 0;
a |= (1 << 9); //delete user
a |= (1 << 17); //delete group
a |= (1 << 25); //delete other
//a = 10000000100000001000000000
private static final DELETE = 33686016; //10,0000,0010,0000,0010,0000,0000
//========= calculate modify constant ==========
a = 0;
a |= (1 << (7 + 7)); //modify user
a |= (1 << (15 + 7)); //modify group
a |= (1 << (23 + 7)); //modify other
//a = 1000000010000000100000000000000
private static final MODIFY = 1077952512; // 100,0000,0100,0000,0100,0000,0000,0000
// now, if i want to set read-write-delete-modify, I will do the following:
int rwdm = 0 | READ | WRITE | DELETE | MODIFY;
// and put the value to the header... am I right?
if right, the only problem remains the question 1: how do I make ACTION operation and how to set the headers.
Note that the text you quote from the Bluetooth FTP specification mentions three headers: ActionId, Name, DestName. So you need to add one NAME header and one DestName header. Jsr-82 apparently doesn't define the const for that (new) header so quoting from the OBEX specification:
MODIFICATION
2.1 OBEX Headers
HI identifier | Header name | Description
0x94 Action Id Specifies the action to be performed (used in ACTION operation)
0x15 DestName The destination object name (used in certain ACTION operations)
0xD6 Permissions 4 byte bit mask for setting permissions
0x17 to 0x2F Reserved for future use. This range includes all combinations of the upper 2 bits
So create the following etc. (My Java's a bit rusty)
static final int DEST_NAME = 0x15;
And use that in your code.
[ADD] All the operations (actions) that are actions use the ACTION operation! :-,) That is use OBEX opcode ACTION instead of PUT or GET etc. The value of opcode ACTION is 0x86.
I'm reading this from "OBEX_Errata Compiled For 1.3.pdf". The IrDA did charge for specifications but seem to now provide them on request (http://www.irda.org). Ask for a copy of the latest OBEX specs (1.5 IIRC). I've done so myself but not yet got a response. Or you could maybe try googling for say "move/rename object action" to get that '1.3 Errata' PDF.
Anyway, if Java prevents you from using new Opcodes (only allowing GET and PUT) and also prevents you from using new HeaderId values then you can't proceed anyway. :-( *(There's no reason for them to do that as HeaderId encodes the data type it contains).
After having another look at the Java API I can't see any way of sending an arbitrary command over ClientSession. You'd have to manually build the packets, connect to the OBEX service and then send and receive packets over that connection. It isn't too difficult to build the packets...

Resources