Unicast/multicast packet using xdp/tc eBPF - bpf

I am trying to design a load balancer using ebpf. I want to transmit the incoming packet to different destinations (devices connected in the same network). Although I have used the clone_bpf_redirect() helper function to redirect the packet to real/ virtual interfaces and it's working fine, now I want to broadcast/unicast the packet to other devices connected in the same network.
XDP does not support it, as far as I know. Therefore, using tc bpf hook. Is there any helper function or which action should I use? Can anyone please guide me on how can I do this?
**eBpf load divider**: 192.168.98.178 (load divider)
**Receiver 1**: 192.168.98.131
**Receiver 2**: 192.168.98.138
iph->daddr = htonl(3232260739); //Dest: 192.168.98.131
iph->check = 0;
iph->check = checksum((unsigned short *)iph, sizeof(struct iphdr));
// Update upd packet checksum of
sum = old_daddr + (~ntohs(*(unsigned short *)&iph->daddr) & 0xffff);
sum += ntohs(udp->check);
sum = (sum & 0xffff) + (sum>>16);
udp->check = htons(sum + (sum>>16) - 1);
// clone the packet and redirect to infdex
bpf_clone_redirect(skb, skb->ifindex, 0);
//clone the packet and redirect to infdex (virtual interface 2)
bpf_clone_redirect(skb, skb->ifindex + 2, 0);
//clone the packet and redirect to infdex (virtual interface 4)
bpf_clone_redirect(skb, skb->ifindex + 4, 0);
return TC_ACT_OK;
// Or
// return TC_ACT_REDIRECT;
sudo tc filter add dev ens33 ingress bpf da obj bpf_loadbalancer.o sec ingress
after this, I am getting the 1 packet to 3 different ifindex but I want to get the same packet to other devices connected into the network. How can I redirect the packet out of the device, not the interfaces?

Related

One server and multiple clients in NS-3

I want to simulate a server that receives packets from multiple clients and process the data of these packets simultaneously together in NS-3. I have simulated one single server and client in NS-3 by modifying udp-echo-server and udp-echo-client applications in NS-3. Now, for implementing multiple clients, I modified the end lines of StartApplication function in udp-echo-server application as follows:
if((childpid=fork())==0)
{
m_socket->SetRecvCallback (MakeCallback(&UdpEchoServer::HandleRead, this));
m_socket6->SetRecvCallback (MakeCallback(&UdpEchoServer::HandleRead, this));
}
But it does not work. Actually, by connecting two clients, it just reads the first client and ignores the second client. It just runs StartApplication function once. Can anyone help me with this?
Thanks
The fundamental problem with what you're trying to do is that ns-3 is a single threaded simulator. You should not use fork to simulate forking. If you want multiple clients, you have to explicitly create them. I have quickly whipped up a simple example:
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
// simple udp multi-client, single-server simulation to answer
// https://stackoverflow.com/q/59632211/13040392
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/ipv4-global-routing-helper.h"
#include "ns3/applications-module.h"
#include "ns3/point-to-point-grid.h"
#include "ns3/flow-monitor-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("UdpMultiClient");
int
main(int argc, char *argv[]) {
// create grid structure of network
// not necessary. Could just create topology manually
PointToPointHelper p2pLink;
PointToPointGridHelper grid (2, 2, p2pLink);
InternetStackHelper stack;
grid.InstallStack(stack);
// assign IP addresses to NetDevices
grid.AssignIpv4Addresses (Ipv4AddressHelper ("10.1.1.0", "255.255.255.0"),
Ipv4AddressHelper ("10.2.1.0", "255.255.255.0"));
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
// configure and install server app
int serverPort = 8080;
UdpEchoServerHelper serverApp (serverPort);
serverApp.Install(grid.GetNode(0,0));
Address serverAddress = InetSocketAddress(grid.GetIpv4Address(0,0), serverPort);
// configure and install client apps
UdpEchoClientHelper clientApp (serverAddress);
clientApp.Install(grid.GetNode(0,1));
clientApp.Install(grid.GetNode(1,0));
clientApp.Install(grid.GetNode(1,1));
// install FlowMonitor to collect simulation statistics
FlowMonitorHelper flowHelper;
Ptr<FlowMonitor> flowMonitor = flowHelper.InstallAll();
// configure and run simulation
Simulator::Stop(Seconds(10));
NS_LOG_UNCOND("Starting simulation.");
Simulator::Run();
Simulator::Destroy();
NS_LOG_UNCOND("Simulation completed.");
// simulation complete
// get statistics of simlation from FlowMonitor
flowMonitor->CheckForLostPackets();
std::map<FlowId, FlowMonitor::FlowStats> stats = flowMonitor->GetFlowStats();
uint64_t txPacketsum = 0;
uint64_t rxPacketsum = 0;
uint64_t DropPacketsum = 0;
uint64_t LostPacketsum = 0;
double Delaysum = 0;
for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin(); i != stats.end(); ++i) {
txPacketsum += i->second.txPackets;
rxPacketsum += i->second.rxPackets;
LostPacketsum += i->second.lostPackets;
DropPacketsum += i->second.packetsDropped.size();
Delaysum += i->second.delaySum.GetSeconds();
}
NS_LOG_UNCOND(std::endl << " SIMULATION STATISTICS");
NS_LOG_UNCOND(" All Tx Packets: " << txPacketsum);
NS_LOG_UNCOND(" All Rx Packets: " << rxPacketsum);
NS_LOG_UNCOND(" All Delay: " << Delaysum / txPacketsum);
NS_LOG_UNCOND(" All Lost Packets: " << LostPacketsum);
NS_LOG_UNCOND(" All Drop Packets: " << DropPacketsum);
NS_LOG_UNCOND(" Packets Delivery Ratio: " << ((rxPacketsum * 100) / txPacketsum) << "%");
NS_LOG_UNCOND(" Packets Lost Ratio: " << ((LostPacketsum * 100) / txPacketsum) << "%");
// flowMonitor->SerializeToXmlFile("test.xml", true, true);
return 0;
}
As a quick note, in
UdpEchoClientHelper clientApp (serverAddress);
clientApp.Install(grid.GetNode(0,1));
clientApp.Install(grid.GetNode(1,0));
clientApp.Install(grid.GetNode(1,1));
we installed the UdpEchoClient on three Nodes. According to the documentation for this Application, UdpEchoClient sends a packet every 1000000000 ns = 1 s by default. Since we set the length of the simulation to 10 seconds using Simulator::Stop(Seconds(10));, we expect that each client will send 10 packets to the server. So, a total of 30 packets should be sent by clients. Also, since we are using UdpEchoServerHelper on the server, each packet will be echoed back by the server. Therefore, a total of 30 x 2 = 60 packets should be transmitted on the network.
The output of the script is
Starting simulation.
Simulation completed.
SIMULATION STATISTICS
All Tx Packets: 60
All Rx Packets: 60
All Delay: 0.0423177
All Lost Packets: 0
All Drop Packets: 0
Packets Delivery Ratio: 100%
Packets Lost Ratio: 0%
This answer actually demonstrates several features of ns-3, so feel free to ask any followup questions. I highly encourage you to check out the ns-3 documentation for classes you haven't encountered yet.

Read UART transmision Input buffer in Matlab

I'm trying to make a serial communication between two ESP8266 Wifi chips.
To start, I tried sending a sample data 10 times in a for loop. Here is the code:
Transmiter:
for Packets = 1 : 10
SendData(client,Data(Packets));
end
Receiver:
Packets = 1
while(1)
Data(Packets) = ReceiveData(Server);
Packets = Packets + 1;
if (packets == 10)
break
end
end
it works good. The problem is when I want to send data with some delays, the transmitter should connect to receiver again and the server (receiver) receives some data indicating that connection is made again.
The received Buffer should be:
+IPD,0,1024:ùüþþþýýþþÿÿûûýþýûúþÿúóýÿþþþþþýúøûýþ...
but after reconnecting the received Buffer is:
0,CLOSED %Receiver Prompt, disconnected from Transmiter
0,CONNECT %Receiver Prompt,connected to Transmiter
+IPD,0,1024:ùüþþþýýþþÿÿûûýþýûúþÿúóýÿþþþþþýúøûýþ...
The remaining part of data will be read in next packet and same for next packets.
what should I do to receive just the data?
The send and receive functions:
function ReceivedBuffer = ReceiveData(SerialPort)
ReceivedBuffer = fread(server,1038); %Size data = 1038 Bytes
end
function SendData(SerialPort,Data)
fwrite(SerialPort,Data);
end

Set a TCP port > 65535 with pcap and dnet

I have been injecting packets on the network and watching the effects via wireshark. I am able to correctly set and change tcp ports and set the source and destination. However, I am now having an issue. One of the things I need to do is to set a source port from port 66,000. Every time I try it just puts the number to 1163 in wireshark which is because it is supposed to be a short integer. Does anyone know how to make it accept the big number. I know the big endian and htonl should work so I tried that as well but that didn't solve the issue.
Here is the code I am using
void extract(u_char *user, struct pcap_pkthdr *h, u_char *pack ) {
struct eth_hdr *ethhdr;
struct ip_hdr *iphdr;
struct tcp_hdr *tcphdr;
ethhdr = (struct eth_hdr *)pack;
iphdr = (struct ip_hdr *)(pack + ETH_HDR_LEN);
tcphdr = (struct tcp_hdr *) (pack + ETH_HDR_LEN + (4*iphdr->ip_hl));
//Set the ports
tcphdr->th_sport = htons(66666);
tcphdr->th_dport = htons(atoi(destString));
The port number is 16 bit. With 16 bit you can get only up to 65535. No way around it. See also the TCP header at http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure.

How can I do a tcp syn port scan with golang?

I'm trying to write a tcp syn port scanner with golang, I found a solution in C version here: http://www.binarytides.com/tcp-syn-portscan-in-c-with-linux-sockets/
I'd like to implement it in go, how can I send a tcp header like this in golang:
//TCP Header
tcph->source = htons ( source_port );
tcph->dest = htons (80);
tcph->seq = htonl(1105024978);
tcph->ack_seq = 0;
tcph->doff = sizeof(struct tcphdr) / 4; //Size of tcp header
tcph->fin=0;
tcph->syn=1;
tcph->rst=0;
tcph->psh=0;
tcph->ack=0;
tcph->urg=0;
tcph->window = htons ( 14600 ); // maximum allowed window size
tcph->check = 0; //if you set a checksum to zero, your kernel's IP stack should fill in the correct checksum during transmission
tcph->urg_ptr = 0;
Do I have to use syscall or cgo? I'm really appreciated if someone could help me out.
You're going to want to use syscall. However the syscall package is not necessarily portable across different Operating Systems so if that matters to you then you'll have to write per os versions and use the file_os.go naming scheme to hold the os specific code.

Car OBDII WLAN protocol

I am currently searching for the specification of the WLAN protocoll to get OBDII data. There are some ELM327 similar adapter on the market which enables iPhone to connect to a OBDII interface with WLAN. This because Bluetooth serial port is scrambled because of the accessories interface. Other programs like Torque for android can also use this communication protocol. However I did not find the specs for creating a network client.
Any help is welcomed,
Thanks
Ok, after some more research, I found two sources:
Michael Gile has an open source library for iOS devices, meant for communicating with OBDII WiFi as well as Bluetooth devices.
PLX devices (creators of the KiWi) have a description how to communicate with the KiWi. The description is too large to include here, but it boils down to:
Connect using WiFi (sockets)
Wait until the device returns >
Issue command and await response
Requesting information can be done by sending a command in this format (ASCII characters):
MM PP\r
where MM is the test mode, PP is the PID, and \r is a carriage return (hex: 0x0d). All whitespace characters are ignored by the Kiwi. *Test modes 03 and 04 do not require a PID value.
The 'test modes' that are spoken of, are the ten diagnostic modes as defined in the SAE J1979 standard:
Test mode Description
01 Show current data
02 Show freeze frame data
03 Show diagnostic trouble codes
04 Clear trouble codes and stored values
05 Test results, oxygen sensors
06 Test results, non-continuously monitored
07 Show 'pending' trouble codes
08 Special control mode
09 Request vehicle information
0A Request permanent trouble codes
The PID values are the codes for the sensors in the car. A (non-exhaustive)list of possible PID values is on Wikipedia.
here what i do in C and socket:
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
char *ip = "192.168.0.10";
char str [128];
int i;
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(35000);
if(inet_pton(AF_INET, ip, &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
printf ("reading...\n");
strcpy (str,"AT Z\x0d");
sleep(2);
write (sockfd, str, strlen (str));
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
printf ("received: ");
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
printf ("\r\ntype: ");
fgets (str, sizeof (str), stdin);
i = strlen (str);
if (str [i-1] == 0x0a)
str [i-1] = 0;
strcat (str, "\x0d");
write (sockfd, str, strlen (str));
printf ("\r\n");
}
type 1 or 2 enter, you should see the prompt: ELM327
then after that, type whatever you want, for ex.: AT RV (will show voltage)
then use this pdf for all code:
https://www.obd-2.de/carcode/dl/ELM327DS.pdf
Have a look at ELM327 datasheet
Wifi dongles transparently bind the ELM327 RS232 port to a TCP server.
There's not really a WIFI protocol. You can use the ELM327 protocol via a raw TCP connection instead.
You can sent AT commands and OBD2 commands known as PID's with the telnet command:
telnet 192.168.0.1 35000
On succesful connection you can try to send:
AT Z
and the server should respond with "ELM327" and a version number.