I have a codebase in C that parses network packets, and it seems to work with UDP just fine. Except for (the first packet of) TFTP. Is the Ubuntu tftp client (which is actually the BSD netkit TFTP client) faulty in this respect? I have noticed, for example, that when you send the same file, it always sends the same checksum (even though, over different runs, the source port is different, as one would expect, and the UDP checksum is supposed to incorporate the UDP source port).
Am I making the wrong assumptions? Is TFTP different when it comes to UDP header checksums? I know it's not necessarily a programming question, but it's holding up my programming, that's for sure.
What I hadn't noticed is that virtual machines offload the formulation of packets; my tests ran on virtual machines guests. So the answer is, if you ever have corrupt packets on VM's, consult with this link:
http://www.linuxquestions.org/questions/linux-networking-3/help-needed-disabling-tcp-udp-checksum-offloading-in-debian-880233/
follow up, and try again.
Related
I want to be able to simulate an incoming packet on a certain physical network interface.
Specifically, given an array of bytes and an interface name, I want to be able to make that interface think a packet containing those bytes arrived from another interface (most likely on another machine).
I've implemented the code that prepares the packet, but I'm unsure what the next step is.
I should point out that I actually need to feed the interface with my bytes, and not use a workaround that might produce a similar results in other machines (I've seen answers to other questions mentioning the loopback interface and external tools). This code is supposed to simulate traffic on a machine that's expecting to receive traffic from certain sources via specific interfaces. Anything else will be ignored by the machine.
I'm going to stick my neck out and say this is not possible without kernel modifications, and possibly driver modifications. Note that:
There are plenty of ways of generating egress packets through a particular interface, including libpcap. But you want to generate ingress packets.
There are plenty of ways of generating ingress packets that are not through a physical interface - this is what tap/tun devices are for.
If you modify the kernel to allow direct injection of packets into a device's receive queue, that may have unexpected effects, and is still not going to be an accurate simulation of the packets arriving in hardware (e.g. they will not be constrained to the same MTU etc). Perhaps you can build an iptables extension that fools the kernel into thinking the packet came from a different interface; I'm not sure that will do what you need though.
If all you need is simulation (and you are happy with a complete simulation), build a tap/tun driver, and rename the tap interface to eth0 or similar.
Depending on which network layer you're trying to simulate, there may be a work-around.
I have had success getting ip packets into the ingress queue with an ethernet 'hairpin'. That is, by setting the source and destination MAC address to the local interface, sending the packet results in it first appearing as an egress packet, then being 'hairpinned' and also appearing as an ingress packet.
This at least works under linux using pcapplusplus (libpcap under the hood), with my wireless interface. Your millage may vary.
This will obviously only suit your needs if you're OK with modifying the ethernet header, ie only simulating a higher layer.
Here is a snippet of c++ where I spoof a rst tcp packet for a local socket:
//always use the actual device source MAC, even if we're spoofing the remote rst
// this produces a 'hairpin' from the egress to the ingress on the interface so the tcp stack actually processes the packet
// required because the tcp stack doesn't process egress packets (at least on a linux wireless interface)
pcpp::EthLayer eth(localMAC,localMAC);
pcpp::IPv4Layer ip(remoteIP, localIP);
pcpp::TcpLayer tcp(remotePort, localPort);
pcpp::Packet pac(60);
ip.getIPv4Header()->timeToLive = 255;
tcp.getTcpHeader()->rstFlag = 1;
tcp.getTcpHeader()->ackFlag = 1;
tcp.getTcpHeader()->ackNumber = pcpp::hostToNet32(src.Ack);
tcp.getTcpHeader()->sequenceNumber = pcpp::hostToNet32(src.Seq);
pac.addLayer(ð);
pac.addLayer(&ip);
pac.addLayer(&tcp);
pac.computeCalculateFields();
dev->sendPacket(&pac);
EDIT: the same code works on windows on an ethernet interface. It doesn't seem to do the same 'hairpin' judging from wireshark, but the tcp stack does process the packets.
Another solution is to create a new dummy network device driver, which will have the same functionality as the loopback interface (i.e. it will be dummy). After that you can wrap up a creation of simple tcp packet and specify in the source and destination addresses the addresses of the two network devices.
It sounds a little hard but it's worth trying - you'll learn a lot for the networking and tcp/ip stack in linux.
I've already started a question here (link) about this project I'm doing, and I keep having lots of problems with this.
In my earlier question I wanted to read from a same machine udp multicast and I find out how to do it, but not with ipmidi.(If you didn't read the previous question linked above, ipmidi is a tool for mac/win which allows me to send midi events through an UDP multicast).
I've been working around with wireshark and managed to see that ipmidi is sending datagrams to the ip 225.0.0.37, port 21928, wich tells me that is, in fact, a multicast.
Then I used this code (the listener) to try to echo the datagrams sent by ipmidi with no success (I changed the multicast ip and the port).
After this I decided to try to run this code from the raspberry pi, since I only wanted it to run in my mac for testing purposes, I went to the real thing.
In my raspi I compiled the code again and gcc claimed that setsockopt() had an invalid argument. perror() was useful enough to tell me that the problem was here:
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))
So I removed the part where it asks for a multicast address to the kernel and made it a simple listening socket at port 21928, but it still won't work.
I have my mac sending midi through ethernet to the raspi.
Now, the actual questions:
I'm now doubting my multicast, so called, knowledge: if my mac is multicasting ipmidi's datagrams, it means the datagrams are being sended through all the possible places in my mac, right? I mean, the ip 225.0.0.37 means multicast through wifi and ethernet or I have to route it to the network interface of my choice?
Since my raspi is, allegedly, receiving the datagrams through the ethernet, making my program listen at the ipmidi's datagram destination port would be enough or do I have to tell it explicitly 'where' those datagrams came from?
Is there an easier way to make a multicast receiving app, like an api for C/C++? I'm currently using C style sockets, as you could see in the code I linked, but this is not the main purpose for the program I'm doing and I find myself spending lots of time just learning about networking instead of focusing on the real thing.
Sorry for the long question, lots of doubts and I wanted to be in context.
Thanks for the help!
Just listening on the port isn't enough - you need to join the multicast group if you want to see datagrams sent to that group.
The "Invalid Argument" error from your setsockopt() call probably means that your mreq argument was bad. For the multicast address you've given, you should be doing:
struct ip_mreqn mreq;
inet_aton("225.0.0.37", &mreq.imr_multiaddr);
mreq.imr_address.s_addr = htonl(INADDR_ANY);
mreq.imr_ifindex = 0;
So, after some research and trial/error my problem was the raspberry pi being hidden behind my mac.
Since my mac was giving internet to the raspberry pi, the multicast wasn't being caught by the raspi, hence the reason why it failed to join it.
About the setsockopt, I made the same mistake has I had originally in the question: 255 instead of 225 in the multicast ip. Because of this, the options IPPROTO_IP and IP_ADD_MEMBERSHIP were wrong, and the program would block there.
Is working now and I already started to code the midi specification.
Thanks for the help, specially to #caf.
I am using libpcap library. I have made one packet sniffer C program using pcap.h. Now I want to block packets coming on port 23 on my computer via eth0 device. I tried pcap_filter function but it is not useful for blocking.
Please explain to me how to code this functionality using c program.
Libpcap is just used for packet capturing, i.e. making packets available for use in other programs. It does not perform any network setup, like blocking, opening ports. In this sense pcap is a purely passive monitoring tool.
I am not sure what you want to do. As far as I see it, there are two possibilities:
You actually want to block the packets, so that your computer will not process them in any way. You should use a firewall for that and just block this port. Any decent firewall should be able to do that fairly easy. But you should be aware, that this also means no one will be able to ssh into your system. So if you do that on a remote system, you have effectively locked out yourself.
You still want other programs (sshd) to listen on port 23 but all this traffic is annoying you in your application. Libpcap has a filtering function for that, that is quite powerful. With this function you can pass small scripts to libpcap and have it only report packets that fit. Look up filtering in the pcap documentation for more information. This will however not "block the traffic" just stop pcap from capturing it.
Actually using pcap you are not able to build firewall. This is because packets seen inside your sniffer (built using pcap) are just copy of packets which (with or without sniffer) are consumed by network stack.
In other words: using filters in pcap will cause that you will not see copies of original packets (as far as I know pcap compiles filters and add those to kernel so that on kernel level copy will not be done); anyway original packet will go to network stack anyway.
The solution of your problem most probably could be done by netfilter. You can register in NF_IP_PRE_ROUTING hook and there decide to drop or allow given traffic.
I am currently working on a programming assignment. The assignment is to implement a client,network emulator, and server. The client passes packets to a network emulator, and the network emulator passes to the server. Vice-versa applies as well. The prerequisite for the assignment is that I may only use raw sockets. So I will create my own IP and UDP headers. I have tested my packets with wireshark. They are all correct and in the proper format(it reads them properly).
Another requirement is that the emulator, client and server all have specific ports they must be bound to. Now, I do not understand how to bind a raw socket to a specific port. All my raw sockets receive all traffic on the host address they are bound to. According to man pages, and everywhere else on the internet, including "Unix Network Programming" by Richard Stevens, this is how they are supposed to work. My teacher has not responded to any of my emails and I probably will not be able to ask him until Tuesday.I see two options in front of me. First I can use libpcap to filter from a specific device and then output to my raw socket. I feel this is way out of scope for our assignment though. Or I can filter them after I receive them from the socket. This apparently has a lot of overhead because all the packets are being copied/moved through the kernel. At least, that is my understanding(please feel free to correct me if i'm wrong).
So my question is:
Is their an option or something I can set for this? Where the raw socket will bind to a port? Have I missed something obvious?
Thank you for your time.
--
The man page for raw(7) says:
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).
Edit: You cannot bind a raw socket to a specific port because "port" is a concept in TCP and UDP, not IP. Look at the header diagrams for those three protocols and it should become obvious: you are working at a lower level, where the concept of port is not known.
I would think you're expected to filter the packets in your software. It sounds like the exercise is to learn what the different components of the IP stack do by recreating a simplified piece of it in user space. Normally in the kernel, the IP code would process all packets, verify the IP headers, reassemble fragments, and check the protocol field. If the protocol field is 17 (udp), then it passes it to the UDP code (every UDP packet). It's up to the UDP code to then validate the UDP header and determine if any applications are interested in them based on the destination port.
I imagine your project is expected to more or less mimic this process. Obviously none of it will be as efficient as doing it in the kernel, but since the assignment is to write (part of) an IP stack in user-space, I'd guess efficiency isn't the point of the exercise.
my computer's IP is 192.168.1.101 over eth0.
I want to know what are other active/used IP under 192.168.1.*
I am expecting a list of IP address that is ping-able under 192.168.1.*
How can I do that in C? And preferably in linux platform.
Any C functions available?
There is no built-in function in C that sends ping packet. There is, however, function that just sends packet. There is also a lot of code in the internet that already implements ping.
What you have to do is just take one of them (this for example) and ping in a loop for all addresses in your network.
You should know, however, that ping is not a reliable way of saying which addresses are in use. RFC 792 - Internet Control Message Protocol says:
The Internet Protocol is not designed
to be absolutely reliable. The purpose
of these control messages is to
provide feedback about problems in the
communication environment, not to make
IP reliable. There are still no guarantees that a datagram will be
delivered or a control message will
be returned. Some datagrams may still
be undelivered without any report
of their loss.
which means that any message can be easily lost, with no notification. Furthermore, target does not have to respond.