Unable to set default gateway from python - python

I have written code to set default gateway using ioctl in C. I have a function to set the gateway and the usual main function. When I compile and run the code it works fine, but when I turn it into a library and call the main function from python using ctypes the ioctl call fails. Why is this?
Note: Before using ctypes method, I tried to set gateway from python using fcntl, ioctl and socket but it failed with OSError saying invalid arguments.
gateway.c
int setDefaultGW( int sockfd, char* gatewatStr)
{
struct sockaddr_in *dst, *gw, *mask;
struct rtentry route;
in_addr_t gip;
fprintf( stderr,"socket %d\n", sockfd);
fprintf( stderr,"Address %s\n", gatewatStr);
gip = inet_addr(gatewatStr);
fprintf( stderr,"Address %d\n", gip);
memset(&route,0,sizeof(struct rtentry));
dst = (struct sockaddr_in *)(&(route.rt_dst));
gw = (struct sockaddr_in *)(&(route.rt_gateway));
mask = (struct sockaddr_in *)(&(route.rt_genmask));
/* Make sure we're talking about IP here */
dst->sin_family = AF_INET;
gw->sin_family = AF_INET;
mask->sin_family = AF_INET;
/* Set up the data for adding the default route */
dst->sin_addr.s_addr = inet_addr("0.0.0.0");
gw->sin_addr.s_addr = gip;
mask->sin_addr.s_addr = inet_addr("0.0.0.0");
route.rt_metric = 100;
route.rt_flags = RTF_UP | RTF_GATEWAY;
/* Remove this route if it already exists */
ioctl(sockfd,SIOCDELRT,&route);
/* Add the default route */
if( ioctl(sockfd,SIOCADDRT,&route) < 0 )
{
fprintf( stderr,"Adding default route: %d\n", errno);
return -1;
}
fprintf( stdout,"Added default route successfully.\n" );
return 0;
}
int main(){
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("socket creation failed\n");
return;
}
setDefaultGW(sockfd, "192.168.6.1");
return 0;
}
net.py
gatewayFun = ctypes.CDLL("./libgateway.so")
gatewayFun.main()
Running the C binary:
./gateway
socket 3
Address 192.168.6.1
Address 17213632
Added default route successfully.
Running the python script:
# python3 net.py
socket 4
Address 192.168.6.1
Address 17213632
Adding default route: 101

Related

C++ client not receiving any data from Python server

I'm working on a project with a C++ client and a Python server.
int connecting(SOCKET s){
WSADATA wsa;
struct sockaddr_in server;
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
std::cout<<"WSA error";
return 1;
}
if((s=socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET){
std::cout<<"invalid socket";
return 1;
}
server.sin_addr.s_addr = inet_addr("192.168.1.10");
server.sin_family = AF_INET;
server.sin_port = htons(2424);
if(connect(s , (struct sockaddr *)&server , sizeof(server))!=0){
std::cout<<"error connecting";
return 1;
}
else{
return 0;
}
}
void recv_data(SOCKET socket){
char buf[buflen];
recv(socket, buf, buflen, 0);
std::cout<<buf;
}
int main(int argc, char* argv[]){
SOCKET s;
connecting(s);
recv_data(s);
}
Here's the very basic Python server.
import socket
import struct
s=socket.socket()
s.bind(("192.168.1.10", 2424))
s.listen(1)
c, a=s.accept()
print(f"{a}")
data="Hi from server"
c.send(data.encode())
After establishing the connection in the server, the a variable is printed. Nothing is received nor printed in the client-side. I tried putting in a loop the recv() function in the client but it does not work.
You misunderstood argument passing by value...
void f(int x) {
x = 5;
}
int main() {
int j = 7;
f(j);
printf("%d\n", j);
}
What is j? NOT 5! The number 7 was passed into f, where it was stored in the variable x, and then the number 5 was stored in the variable x, which is not the variable j, so j was not changed.
You have this in your program:
int main(int argc, char* argv[]){
SOCKET s;
connecting(s);
recv_data(s);
}
After the call connecting(s) what is s? NOT A SOCKET! Only the variable s inside the function connecting held a socket handle, and the variable s in main is not that variable, so it never got to hold a socket handle. You pass some uninitialized value to recv_data.
The function recv probably reads this random uninitialized value and returns an error code meaning "hey, that isn't a socket handle" but since your code never checked whether it returned an error code, you wouldn't know about this.

C++ behaves differently in Qt, bind() returns EINVAL

I have already checked out bind() return EINVAL and that is not the issue here. Please read through before you get furious about duplication.
I am trying to connect to wpa_supplicant. Basically I'm trying to achieve this using C++:
import os
import select
import socket
interface = "wlp4s0"
wpa_send_path = "/run/wpa_supplicant/"+interface
wpa_recv_path = "/tmp/wpa_ctrl_{pid}-{count}".format(pid=os.getpid(), count=1)
soc = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
soc.bind(wpa_recv_path)
soc.connect(wpa_send_path)
print("> PING")
soc.send(b"PING")
print("<", soc.recv(4096).decode().strip())
from https://gist.github.com/artizirk/cd3980c8ff870eb0bfce68bc26a2676b
And I have done what I wanted but using plain C++. This is the code:
#include <iostream>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#define PATH "/run/wpa_supplicant/wlp4s0"
char path[100] = "/tmp/wpa_ctrl_";
int main(void) {
int ctrl_socket;
char buffer[1024];
struct sockaddr_un socket_addr, send_addr;
memset(&socket_addr, 0, sizeof(struct sockaddr_un));
memset(&send_addr, 0, sizeof(struct sockaddr_un));
socket_addr.sun_family = AF_UNIX;
send_addr.sun_family = AF_UNIX;
strcpy(send_addr.sun_path, PATH);
strcat(path, std::to_string(getpid()).c_str());
strcat(path, "-1");
strcat(socket_addr.sun_path, path);
if ((ctrl_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
std::cerr << "Error creating socket!" << std::endl;
std::exit(EXIT_FAILURE);
}
/* Unlink if already bound */
unlink(socket_addr.sun_path);
if ((connect(ctrl_socket, (struct sockaddr *)&send_addr, SUN_LEN(&send_addr))) == -1) {
std::cerr << "Error connecting to socket!" << std::endl;
std::exit(EXIT_FAILURE);
}
if (bind(ctrl_socket, (const struct sockaddr *)&socket_addr, offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1) == -1) {
perror("Error");
exit(EXIT_FAILURE);
}
send(ctrl_socket, "PING", 5, 0);
recv(ctrl_socket, buffer, 1024, 0);
std::cout << buffer << std::endl;
close(ctrl_socket);
return 0;
}
This code works fine. But when I do it in Qt, bind() always return EINVAL i.e Invalid Arguments. Here's that code:
WPASupplicantControl::WPASupplicantControl(std::string wlan_interface_name)
:wpa_send_ctrl_iface(WPA_SEND_CTRL_IFACE_PREFIX + QString::fromStdString(wlan_interface_name)),
wpa_recv_ctrl_iface(
WPA_RECV_CTRL_IFACE_PREFIX +
QString::fromStdString(std::to_string(getpid())) +
"-1"
)
{
struct sockaddr_un send_address, recv_address;
send_address.sun_family = AF_UNIX;
recv_address.sun_family = AF_UNIX;
memset(&send_address, 0, sizeof (send_address));
memset(&recv_address, 0, sizeof (recv_address));
strncpy(send_address.sun_path, wpa_send_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
strncpy(recv_address.sun_path, wpa_recv_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
if ((wpa_control_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
qCritical() << "socket() failed!";
exit(EXIT_FAILURE);
}
/* Attatch to sending and receiving control interfaces */
if (connect(wpa_control_socket, (const struct sockaddr *)&send_address, SUN_LEN(&send_address)) == -1) {
qCritical() << "Error connecting to wpa_supplicant send control iface!";
close(wpa_control_socket);
exit(EXIT_FAILURE);
}
/* Detatch if it's already bound */
unlink(recv_address.sun_path);
if (bind(wpa_control_socket, (const struct sockaddr *)&recv_address, offsetof(struct sockaddr_un, sun_path) + wpa_recv_ctrl_iface.length() + 1) == -1) {
qCritical() << "Error binding to wpa_supplicant recv control iface!";
close(wpa_control_socket);
exit(EXIT_FAILURE);
}
}
A functional dummy project to test this code is at: https://github.com/gaurav712/socket_test
I have checked all the values hundreds of times and they're all fine but still it doesn't work. It just goes upto that connect() call.
I thought I should use something Qt-specific and I found out about QLocalSocket https://doc.qt.io/qt-5/qlocalsocket.html but when I import it, Qt doesn't recognize that class. Maybe its because I'm on Qt 6.x and it is now deprecated(although I didn't find any official deprecation notice thingy). What do I do? What am I doing wrong?
Absolutely nothing to do with Qt: You do a memset to all-0 of the sockaddr structures after you've set the socket's family to AF_UNIX (which is "1" on most platforms). How should the system know you want a local socket?
strncpy will copy at most n bytes from source to dest. If there's no null char within n bytes, it's not going to copy it over. The third parameter to strncpy is usually meant to convey the length of the destination buffer.
Change this:
strncpy(send_address.sun_path, wpa_send_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
strncpy(recv_address.sun_path, wpa_recv_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
To be this:
strncpy(send_address.sun_path,
wpa_send_ctrl_iface.toStdString().c_str(),
sizeof(send_address.sun_path) );
strncpy(recv_address.sun_path,
wpa_recv_ctrl_iface.toStdString().c_str(),
sizeof(recv_address.sun_path));
Also, as discussed in the comments, your length param to bind looks funky as well. Try it both with the above changes.

How to capture a multicast packet programmatically

I have a multicast packet from a capture using tcpdump. I can replay the packet using tcpreplay -i eth0 on.pcap and I can receive it on another machine using tcpdump.
I have tried c code and python code to try and capture this packet without success. I've tried both on MacOS and Raspian (Rpi 3b).
https://mega.nz/#!ELAgBSDL!XZ3EXCkDBsLLwFn8J1ofWuMm4Z7sssOZPuZVEpmRqvs
here is a c code example:
/*
multicast.c
The following program sends or receives multicast packets. If invoked
with one argument, it sends a packet containing the current time to an
arbitrarily chosen multicast group and UDP port. If invoked with no
arguments, it receives and prints these packets. Start it as a sender on
just one host and as a receiver on all the other hosts
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdio.h>
#define EXAMPLE_PORT 2068
#define EXAMPLE_GROUP "226.2.2.2"
main(int argc)
{
struct sockaddr_in addr;
int addrlen, sock, cnt;
struct ip_mreq mreq;
char message[50];
/* set up socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("socket");
exit(1);
}
bzero((char *)&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(EXAMPLE_PORT);
addrlen = sizeof(addr);
if (argc > 1)
{
/* send */
addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP);
while (1)
{
time_t t = time(0);
sprintf(message, "time is %-24.24s", ctime(&t));
printf("sending: %s\n", message);
cnt = sendto(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, addrlen);
if (cnt < 0)
{
perror("sendto");
exit(1);
}
sleep(5);
}
}
else
{
/* receive */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
mreq.imr_multiaddr.s_addr = inet_addr(EXAMPLE_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0)
{
perror("setsockopt mreq");
exit(1);
}
while (1)
{
cnt = recvfrom(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, &addrlen);
if (cnt < 0)
{
perror("recvfrom");
exit(1);
}
else if (cnt == 0)
{
break;
}
printf("%s: message = \"%s\"\n", inet_ntoa(addr.sin_addr), message);
}
}
}
Here is a python example:
#!/usr/bin/env python
import socket
import binascii
import sys
MCAST_GRP = '226.2.2.2'
MCAST_PORT = 2068
MCAST_IFACE = '192.168.168.200'
def joinMcast(mcast_addr,port,if_ip):
"""
Returns a live multicast socket
mcast_addr is a dotted string format of the multicast group
port is an integer of the UDP port you want to receive
if_ip is a dotted string format of the interface you will use
"""
#create a UDP socket
mcastsock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#allow other sockets to bind this port too
mcastsock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#explicitly join the multicast group on the interface specified
mcastsock.setsockopt(socket.SOL_IP,socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(mcast_addr)+socket.inet_aton(if_ip))
#finally bind the socket to start getting data into your socket
mcastsock.bind((mcast_addr,port))
return mcastsock
def main():
sock = joinMcast(MCAST_GRP, MCAST_PORT, MCAST_IFACE)
while True:
print >>sys.stderr, '\nwaiting to receive message'
print sock.recv(1024)
if __name__ == '__main__':
main()

What port number do I specify when receiving a raw ethernet packet?

I would like to sniff packets on a particular Ethernet interface using python.
These packets are received from an FPGA and do not contain any of the usual IP headers. The only header info is the Ethernet header.
I have the following python code which reads raw packets, It's from an example I modified from here.
from socket import *
interface = "em3"
# Create socket connection
sock = socket(AF_PACKET, SOCK_RAW, htons(0x0003))
sock.bind((interface, 0)) #port number
data = sock.recv(1024)
print(data)
sock.close()
I understand that when TCP/UDP sockets are created, port numbers are reserved for use by a specific service. However, I don't know what port number to use for my application. How do I know what port number to use?
Why I'm asking:
I'm asking because the above code doesn't receive any packets from the FPGA, even though when I use tshark (sudo tshark -i em3 -w output.bin) I get two. My interface is in promiscuous mode, and now I'm checking if my port number and protocol types are correct.
austinmarton on GitHub has some code to Receive raw Ethernet frames in Linux. This is not my code, so don't ak me any questions about it, and your mileage may vary. Thanks to #Barmar for the link.
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define DEST_MAC0 0x00
#define DEST_MAC1 0x00
#define DEST_MAC2 0x00
#define DEST_MAC3 0x00
#define DEST_MAC4 0x00
#define DEST_MAC5 0x00
#define ETHER_TYPE 0x0800
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
char sender[INET6_ADDRSTRLEN];
int sockfd, ret, i;
int sockopt;
ssize_t numbytes;
struct ifreq ifopts; /* set promiscuous mode */
struct ifreq if_ip; /* get ip addr */
struct sockaddr_storage their_addr;
uint8_t buf[BUF_SIZ];
char ifName[IFNAMSIZ];
/* Get interface name */
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Header structures */
struct ether_header *eh = (struct ether_header *) buf;
struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct iphdr) + sizeof(struct ether_header));
memset(&if_ip, 0, sizeof(struct ifreq));
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
perror("listener: socket");
return -1;
}
/* Set interface to promiscuous mode - do we need to do this every time? */
strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
/* Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(sockfd);
exit(EXIT_FAILURE);
}
/* Bind to device */
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(sockfd);
exit(EXIT_FAILURE);
}
repeat: printf("listener: Waiting to recvfrom...\n");
numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
printf("listener: got packet %lu bytes\n", numbytes);
/* Check the packet is for me */
if (eh->ether_dhost[0] == DEST_MAC0 &&
eh->ether_dhost[1] == DEST_MAC1 &&
eh->ether_dhost[2] == DEST_MAC2 &&
eh->ether_dhost[3] == DEST_MAC3 &&
eh->ether_dhost[4] == DEST_MAC4 &&
eh->ether_dhost[5] == DEST_MAC5) {
printf("Correct destination MAC address\n");
} else {
printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
eh->ether_dhost[0],
eh->ether_dhost[1],
eh->ether_dhost[2],
eh->ether_dhost[3],
eh->ether_dhost[4],
eh->ether_dhost[5]);
ret = -1;
goto done;
}
/* Get source IP */
((struct sockaddr_in *)&their_addr)->sin_addr.s_addr = iph->saddr;
inet_ntop(AF_INET, &((struct sockaddr_in*)&their_addr)->sin_addr, sender, sizeof sender);
/* Look up my device IP addr if possible */
strncpy(if_ip.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFADDR, &if_ip) >= 0) { /* if we can't check then don't */
printf("Source IP: %s\n My IP: %s\n", sender,
inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
/* ignore if I sent it */
if (strcmp(sender, inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)) == 0) {
printf("but I sent it :(\n");
ret = -1;
goto done;
}
}
/* UDP payload length */
ret = ntohs(udph->len) - sizeof(struct udphdr);
/* Print packet */
printf("\tData:");
for (i=0; i<numbytes; i++) printf("%02x:", buf[i]);
printf("\n");
done: goto repeat;
close(sockfd);
return ret;
}
socket probably not going to work here, since it will use TCP/IP
you can try to use the scapy package to sniff packet from that interface.
check this:
http://www.secdev.org/projects/scapy/doc/usage.html#sniffing

Problems communicating between C and Python programs

I am trying to implement a UDP communication protocol between a C program and a python program. The C program has a structure that it sends through the UDP port (tx_port) as binary data. This program also listens on another port (rx_port) for any received data, and then prints the received binary output to the screen.
The python program listens on tx_port and unpacks the received data and prints it to the screen. Then it repacks the data and sends it back through UDP port (rx_port).
Here are the C and Python programs that I used.
C program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#define BUFLEN 4096
#define RX_PORT 8888
#define TX_PORT 8889
// Structure data
struct data {
long frame_number;
double time;
} tx_data, rx_data;
int dlen = sizeof(tx_data);
struct sockaddr_in si_me, si_other;
int tx_soc;
int slen = sizeof(si_other);
int recv_len;
char* buf;
pthread_t rx_thread;
void* receiver_thread(void *arg)
{
int i =0;
while (1) {
recv_len = recvfrom(tx_soc, buf, sizeof(rx_data), 0, (struct sockaddr *) &si_other, &slen);
printf("\nReceived data : %d\n", recv_len);
for (i = 0; i < recv_len; i++) {
printf("%x ", buf[i]);
}
printf("\n");
fflush(stdout);
};
}
void data_init(void) {
tx_data.frame_number = 0;
tx_data.time = 0;
};
int main(void)
{
// Initialize data
data_init();
//create a UDP socket
if ((tx_soc=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Socket error!");
exit(0);
}
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_other));
memset((char *) &si_other, 0, sizeof(si_other));
// Host socket address
si_me.sin_family = AF_INET;
si_me.sin_port = htons(RX_PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
// Remote socket address
si_other.sin_family = AF_INET;
si_other.sin_port = htons(TX_PORT);
si_other.sin_addr.s_addr = htonl(INADDR_ANY);
//bind sockets to the ports
if( bind(tx_soc, (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
printf("Binding error!");
}
// Start reader thread.
if (pthread_create(&rx_thread, NULL, &receiver_thread, NULL) != 0) {
printf("\ncan't create thread");
}
//keep listening for data
while(1)
{
// Allocate memory for receive buffer.
buf = (char*) malloc(sizeof(rx_data));
// Update data value.
tx_data.frame_number++;
printf("\nFrame numner: %ld", tx_data.frame_number);
fflush(stdout);
// Send data.
if (sendto(tx_soc, (char*)&tx_data, dlen, 0, (struct sockaddr*) &si_other, slen) == -1)
{
printf("Sending error!");
}
sleep(1);
}
close(tx_soc);
return 0;
}
Python program
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import struct
# Packet format string
packet_fmt = ''.join(['i', # Frame number
'd', # Frame time stamp
])
s = struct.Struct(packet_fmt)
class Echo(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
new_data = s.unpack(data)
print new_data
echo_data = s.pack(*new_data)
self.transport.write(echo_data, (host, port))
reactor.listenUDP(8889, Echo())
reactor.run()
When I execute the two programs, I am able to receive data on both sides. I am able to unpack data in python, print it, repack and send it.
But on the C side, the received data does not match the sent data. I have checked on the python side to make sure the repacked data matches the original data.
Here is a sample output from the C and Python programs. I started the python programs first, and then the C program.
What is the mistake I might be making?

Categories