I am trying to design a load balancer using ebpf. I want to redirect the incoming packet to different destinations. Although I have used the bpf_clone_redirect helper function to redirect the packet to real/ virtual interfaces and it's working fine. Now I want to redirect the packet to multiple interfaces at once.
Here is the piece of code I write to redirect the 1 packet.
eth->h_dest[0] = 0xb8;
eth->h_dest[1] = 0x27;
eth->h_dest[2] = 0xeb;
eth->h_dest[3] = 0x42;
eth->h_dest[4] = 0x77;
eth->h_dest[5] = 0x56;
new_port = ntohs( 5302) ;
udp->dest= new_port; //change the destination port
ipaddr = htonl(0xc0a8006c); // Dest: 192.168.98.108
iph->daddr = ipaddr; // Change the destination address
// Calculate the sum_diff for destination address and Port number
sum = bpf_csum_diff((void *)&old1_daddr , 4,(void *)&ipaddr,4 , 0);
sum1 = bpf_csum_diff((void *)&old_port , 4,(void *)&new_port,4 , 0);
ipaddr2 = htonl(0xc0a8006e); // Dest: 192.168.98.110
iph->daddr = ipaddr2; // Change the destination address
//L3 and L4 checksum Update
bpf_l3_csum_replace(skb, IP_CSUM_OFF, 0 , sum,0 );
bpf_l4_csum_replace(skb, UDP_CSUM_OFF , 0, sum +sum1, IS_PSEUDO | sizeof(ipaddr) );
bpf_clone_redirect(skb, skb->ifindex, 0 ); // Packet forward to the destination
//Repeat the same functionality
// Calculate the sum_diff for destination address and Port number
sum = bpf_csum_diff((void *)&old1_daddr , 4,(void *)&ipaddr2,4 , 0);
//L3 and L4 checksum Update
bpf_l3_csum_replace(skb, IP_CSUM_OFF, 0 , sum,0 );
bpf_l4_csum_replace(skb, UDP_CSUM_OFF , 0, sum, IS_PSEUDO | sizeof(ipaddr2) );
bpf_clone_redirect(skb, skb->ifindex, 0 ); // Packet forward to the destination
return TC_ACT_OK;
I am facing the problem to update the MAC address of packet. With the above code i can change the destination address and port number but unable to updat2 the mac address in 2nd clone.
Related
i have an instrument that measures so2 and i have a standard program that makes me see the data, but i need to connect the instrument to a server and send all the data to a database. I used wireshark to see how it comunicate with the software, but i don't understand what method to use to make my program. Here i have the wireshark dump:
the red circle indicates the measure that the instrument made.
P.S. sorry for my bad eng
So i solved my question as i'm about to show:
i made a listener and a caller;
caller:
`from socket import socket, AF_INET, SOCK_DGRAM
SERVER_IP = '192.168.1.99'
PORT_NUMBER = 53700
SIZE = 1024
print ("Test client sending packets to IP {0}, via port {1}\n".format(SERVER_IP, PORT_NUMBER))
mySocket = socket( AF_INET, SOCK_DGRAM )
mySocket.bind(('192.168.1.100', 57806))
while True:
data = bytes.fromhex('014630303430335230303102313103')
mySocket.sendto(data,(SERVER_IP,PORT_NUMBER))
exit()`
listener:
`from socket import socket, gethostbyname, AF_INET, SOCK_DGRAM
import sys
PORT_NUMBER = 57806
SIZE = 1024
hostName = gethostbyname( '' )
mySocket = socket( AF_INET, SOCK_DGRAM )
mySocket.bind( (hostName, PORT_NUMBER) )
print ("Test server listening on port {0}\n".format(PORT_NUMBER))
while True:
(data,addr) = mySocket.recvfrom(SIZE)
print (data)
sys.ext()`
i saw on wireshark that if i sent a request packet copied from the ones that i already have, the instrument would give me back the response; so i setupped a listener on the a choosen port, and now i get all the data!
the highlighted packet is the one i sent from the caller script.
I want to use raw socket to send TCP packets which is a full IP packet(so the packet has IP header, TCP header and TCP payload, but has no ethernet header. The IP source and destination addresses are in a WLAN, 192.168.0.105 and 192.168.0.103), with the following codes
int on;
on = 0;
if ((sendfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("raw socket");
exit(1);
}
if (setsockopt(sendfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
perror("setsockopt");
exit(1);
}
nr_bytes = sendto(sendfd, packet, ip_len, 0, (struct sockaddr*)&client_addr, addr_len);
I use TCPdump to capture the sent-out packet and notice it has added an additional IP header to the IP packet, and the IP protocol number is 255(ip->ip_p is 255). So it has two IP headers(with same pair of src and dst IP), which is unexpected.
what are the problems? thank you!
Using IPPROTO_RAW implicitly enables the option IP_HDRINCL.
In your call to setsockopt() you disable IP_HDRINCL again because you set on = 0.
Try removing the setsockopt() or setting on = 1.
This is a basic client server program on UDP. if client 1 sends a data client 2 will receive and vice versa.
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
//bind the socket to localhost port 1902
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Waiting for connections ...");
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
....
....
//what has to be done here to check a client with IP1, Port 1 is already connected? //
....
....
}
}
In this program, i get a message
New connection , socket fd is 4 , ip is : 127.0.0.1 , port : 44851
Welcome message sent successfully
Adding to list of sockets as 0
New connection , socket fd is 5 , ip is : 127.0.0.1 , port : 44852
Welcome message sent successfully
Adding to list of sockets as 1
After this message i want to check if a particular client with IP1, PORT 1 is connected or not? for example to check if client with ip 127.0.0.1 and port 44852 is already connected? if connected print, required client is already available. Can anyone suggest me a way for this?
It should be pretty obvious how to do this. You are storing client information in a list. So simply loop through the list checking if the ip/port reported by accept() is already in the list, adding it if not. Just make sure to keep the list up to date whenever a client disconnects.
I have a complete program that communicates via UDP protocol. Program runs on a PC with ip 192.168.1.9. When I send specific data, this program responds.
code for sending:
var client = new UdpClient();
IPEndPoint destination = new IPEndPoint(IPAddress.Parse("192.168.1.9"), 1531);
IPAddress localIp = IPAddress.Parse("192.168.1.3");
IPEndPoint source = new IPEndPoint(localIp, 1530);
client.Client.Bind(source);
client.Connect(destination);
byte[] send_buffer = { 170, 170, 0, 0, 1, 1, 86 };
client.Send(send_buffer, send_buffer.Length);
Wireshark captures:
Screen
But my application does not detect anything:
UdpClient listener = new UdpClient(1530);
IPAddress ip = IPAddress.Parse("192.168.1.3");
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 1530);
byte[] receive_byte_array;
while (!done)
{
Console.WriteLine("Waiting for broadcast");
receive_byte_array = listener.Receive(ref groupEP);
}
I need to capture communications from 192.168.9 to 192.168.1.3 on port 1530.
Your sender is binding to local IP 192.168.1.3 on port 1530 as its source, and then sending data to remote IP 192.168.1.9 on port 1531 as the destination.
Your receiver is binding to local IP 0.0.0.0 on port 1530 for receiving data, and then filtering out any inbound data that was NOT sent from remote port 1530 (which it is).
The data is not being sent to the port that the receiver is reading on.
To fix that, you need to either:
change your receiver to bind to port 1531 instead of port 1530:
UdpClient listener = new UdpClient(1531);
change your sender to send the data to port 1530 instead of port 1531:
IPEndPoint destination = new IPEndPoint(IPAddress.Parse("192.168.1.9"), 1530);
I have simple server and client in UDP (WinSocks/C++).
I send datagram client -> server via sendto, and reply from server to client using the ip and port obtained from recvfrom function.
I found out that:
Every sendto from client is being sent from different port
When trying to reply from server Windows returns WSAECONNRESET (which mean that port is closed - http://support.microsoft.com/kb/263823)
How can I properly answer client from server (ie force port binding on client when sending using sendto?)
Edit: Adding some source code:
bool InitClient()
{
internal->sock = socket(PF_INET, SOCK_DGRAM, 0);
char8 yes = 1;
setsockopt(internal->sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int32));
return internal->sock != -1;
}
void Send(const IpAddress & target, const uint16 port, const char8 * data, int32 size )
{
sockaddr_in trgt;
memset(&trgt, 0, sizeof(trgt));
trgt.sin_family = AF_INET;
trgt.sin_port = htons(port);
trgt.sin_addr.s_addr = target.GetRaw();
if(sendto(internal->sock, (const char8 *)data, size, 0, (PSOCKADDR)&trgt, sizeof(trgt)) == SOCKET_ERROR)
{
LOG("Network sending error: %d", WSAGetLastError());
}
}
Call the "bind" function to specify a local port to send from. Example of using port 4567 below. Make sure to check the return value from bind.Call this code after you create the socket.
sockaddr_in local = {};
local.family = AF_INET;
local.port = htons(4567);
local.addr = INADDR_ANY;
bind(internal->sock,(sockaddr*)&local, sizeof(local));
If you bind to port zero instead of 4567 then the os will pick a random port for you and use it for all subsequent send and receives. You can call getsockname to discover which port the os picked for you after calling bind.