I'm trying to send udp packet using socket raw with special structure sockaddr_ll, but I'm getting only an ethernet header with trailer and ip header without udp header. I would like to send a normal udp packet without the trailer and get my message. I checked the package using wireshark. How can I fix this?
My packet:
My code:
int main(int argc, char *argv[])
{
int sockfd;
struct ifreq if_idx;
struct ifreq if_mac;
struct ifreq ifreq_ip;
int tx_len = 0;
unsigned char* sendbuf;
sendbuf=(unsigned char*)malloc(64);
memset(sendbuf,0,64);
struct ether_header *eh = (struct ether_header *) sendbuf;
struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
struct udphdr *uph = (struct udphdr *) (sendbuf + sizeof(struct ether_header) + sizeof(struct iphdr));
struct sockaddr_ll socket_address;
char ifName[IFNAMSIZ];
/* Get interface name */
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Open RAW socket to send on */
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("socket");
}
/* Get the index of the interface to send on */
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
perror("SIOCGIFINDEX");
/* Get the MAC address of the interface to send on */
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
/* get ip */
memset(&ifreq_ip,0,sizeof(ifreq_ip));
strncpy(ifreq_ip.ifr_name,ifName,IFNAMSIZ-1);
if(ioctl(sockfd,SIOCGIFADDR,&ifreq_ip)<0)
{
printf("error in SIOCGIFADDR \n");
}
/* Construct the Ethernet header */
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = MY_DEST_MAC0;
eh->ether_dhost[1] = MY_DEST_MAC1;
eh->ether_dhost[2] = MY_DEST_MAC2;
eh->ether_dhost[3] = MY_DEST_MAC3;
eh->ether_dhost[4] = MY_DEST_MAC4;
eh->ether_dhost[5] = MY_DEST_MAC5;
/* Ethertype field */
eh->ether_type = htons(ETH_P_IP);
tx_len += sizeof(struct ether_header);
/* ip header */
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof (struct iphdr));
iph->id = htonl (54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
iph->daddr = inet_addr ( "127.0.0.1" );
//Ip checksum
iph->check = csum ((unsigned short *) sendbuf, iph->tot_len);
tx_len += sizeof(struct iphdr);
uph->source = htons(80);
uph->dest = htons(43521);
uph->check = 0;
tx_len+= sizeof(struct udphdr);
sendbuf[tx_len++] = 0xAA;
sendbuf[tx_len++] = 0xBB;
sendbuf[tx_len++] = 0xCC;
sendbuf[tx_len++] = 0xDD;
sendbuf[tx_len++] = 0xEE;
uph->len = htons((tx_len - sizeof(struct iphdr) - sizeof(struct ethhdr)));
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = MY_DEST_MAC0;
socket_address.sll_addr[1] = MY_DEST_MAC1;
socket_address.sll_addr[2] = MY_DEST_MAC2;
socket_address.sll_addr[3] = MY_DEST_MAC3;
socket_address.sll_addr[4] = MY_DEST_MAC4;
socket_address.sll_addr[5] = MY_DEST_MAC5;
/* Send packet */
if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
The IP Total Length field is only 20 bytes, which is just the size of the IP Header, so as far as IP is concerned, there is no payload. You need to ensure that the IP Total Length field is set to the size of the IP header plus the size of the entire payload. In particular, this line is wrong:
iph->tot_len = htons(sizeof (struct iphdr));
Related
I implement IPv6 in a network engine. I'm on the function to recv packet with UDP. This function retrieve the destination ip also with the cmsghdr structure. I have the following code
int UDPSocket::read_from_to(string& paquet, string& from, string& to, struct timeval *time_kernel /* = NULL */) {
char buffer[65535];
iovec i;
i.iov_base = buffer; // PACKET BUFFER
i.iov_len = 65535;
// A struct for the source IP address
sockaddr_in sa;
sockaddr_in6 sa_ipv6;
if (CompatibilityIPv4::Instance()->canIPv6()) {
bzero((char *) &sa_ipv6, sizeof(sa_ipv6));
sa_ipv6.sin6_family = AF_INET6;
} else {
bzero((char *) &sa, sizeof(sa));
sa.sin_family = AF_INET;
}
// Some place to store the destination address, see man cmsg
int cmsgsize = 0;
if (CompatibilityIPv4::Instance()->canIPv6()) {
cmsgsize = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(struct timeval));
} else {
cmsgsize = CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(struct timeval));
}
char cmsg[cmsgsize];
// The actual structure for recvmsg
msghdr m;
bzero(&m,sizeof(m));
if (CompatibilityIPv4::Instance()->canIPv6()) {
m.msg_name = &sa_ipv6;
m.msg_namelen = sizeof(sa_ipv6);
} else {
m.msg_name = &sa; // SOURCE IP
m.msg_namelen = sizeof(sa);
}
m.msg_iov = &i; // PACKET BUFFER, indirect
m.msg_iovlen = 1;
m.msg_control = cmsg; // FOR DESTINATION IP
m.msg_controllen = sizeof(cmsg);
// <<<< ACTUAL SYSTEM CALL >>>>
int p=recvmsg(fd, &m, 0);
std::cout << m.msg_controllen << std::endl;
In IPv4 at the end the value of m.msg_controllen is > 0 but in IPv6 it's always 0 so I can't fetch the destination IP. The sendto function is the same for IPv4/IPv6 :
if (CompatibilityIPv4::Instance()->canIPv6()) {
sockaddr_in6 sa;
bzero((char *) &sa, sizeof(sa));
sa.sin6_family = AF_INET6;
inet_pton(AF_INET6, k[0].c_str(), &sa.sin6_addr);
sa.sin6_port = htons(port);
p = sendto(fd,paquet.c_str(),paquet.size(),0,(sockaddr*)&sa, sizeof(sa));
} else {
sockaddr_in sa;
bzero((char *) &sa, sizeof(sa));
sa.sin_family = AF_INET;
inet_aton(k[0].c_str(),&sa.sin_addr);
sa.sin_port = htons(port);
p = sendto(fd,paquet.c_str(),paquet.size(),0,(sockaddr*)&sa, sizeof(sa));
}
Do you have any ideas why my m.msg_controllen is 0 on IPV6 ?
Thanks a lot !
I have solved it. I was using IPV6_PKTINFO instead of IPV6_RECVPKTINFO in my setsockopt.
I have a Raspberry Pi that interface a CAN Bus though SPI. I've installed canutils and if I do a cansend the message is received by the controller and applied, but if I do it through code it doesn't. It must be something that I'm doing wrong in building the frame, so if somebody can help me to point out my error I'll appreciate it.
This is the cansend message that I send.
cansend can0 01f801f2#1212121223232323
This is my code to send the same message. The code runs in a pthread.
void *CANUpdate(void *userParam)
{
struct sockaddr_can addr;
struct ifreq ifr;
const char *ifname = "can0";
int can_s;
if ((can_s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
LogEntry(LOG_ERR, "Error while opening socket\n");
return 0;
}
strcpy(ifr.ifr_name, ifname);
ioctl(can_s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(can_s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
LogEntry(LOG_ERR, "Error in CAN socket bind\n");
return 0;
}
while (!stopServer)
{
if (can_s)
{
struct can_frame frame;
frame.can_id = 0x01f801f2;
frame.can_dlc = 8;
frame.data[0] = 0x12;
frame.data[1] = 0x12;
frame.data[2] = 0x12;
frame.data[3] = 0x12;
frame.data[4] = 0x34;
frame.data[5] = 0x34;
frame.data[6] = 0x34;
frame.data[7] = 0x34;
int res = write(can_s, &frame, sizeof(struct can_frame));
}
msleep(800);
}
}
There was basically 2 problems with the code.
1. I should have used the canfd_frame struct, and I should've 0'ed the values. Here is the code that worked at the end
void *CANUpdate(void *userParam)
{
struct sockaddr_can addr;
struct ifreq ifr;
const char *ifname = "can0";
int can_s;
if ((can_s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
LogEntry(LOG_ERR, "Error while opening socket\n");
return 0;
}
strcpy(ifr.ifr_name, ifname);
ioctl(can_s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
setsockopt(can_s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
if (bind(can_s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
LogEntry(LOG_ERR, "Error in CAN socket bind\n");
return 0;
}
while (!stopServer)
{
if (can_s)
{
struct canfd_frame frame;
memset(&frame, 0, sizeof(frame)); /* init CAN FD frame, e.g. LEN = 0 */
frame.can_id = 0x01f801f2;
frame.len = 8;
if (!(frame.can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
frame.can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
frame.data[0] = 0x12;
frame.data[1] = 0x12;
frame.data[2] = 0x12;
frame.data[3] = 0x12;
frame.data[4] = 0x34;
frame.data[5] = 0x34;
frame.data[6] = 0x34;
frame.data[7] = 0x34;
if(write(can_s, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame);
LogEntry(LOG_ERR, "Unable to write CAN message\n");
}
msleep(800);
}
}
I am trying to send struct over tcp socket. I am a newbie in socket programming, I did try the options suggested here already but those did not serve my purpose. Could someone pls help?
I have written Server.cpp and Client.cpp and both are compiling properly. However, when I am executing my Server to listen to the Client, I am not sure if the Server is able to recieve the structure from Client or not. Also, how can I read this structure once it is received?
Server.cpp
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
//cout<<UE1.imsi<<"\n"<<UE1.Net<<"\n";
int sock, cli, receive;
sockaddr_in server, client;
unsigned int len;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(10000);
//cout<<htons(10000);
server.sin_addr.s_addr = INADDR_ANY;
//cout<<INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(struct sockaddr_in);
if((bind(sock, (struct sockaddr *)&server, len)) == -1)
{
perror("Bind:");
exit(-1);
}
if((listen(sock, 5)) == -1)
{
perror("Listen:");
exit(-1);
}
while(1)
{
cli = accept(sock,(struct sockaddr *)&client, &len);
if(cli == -1)
{
perror("Accept");
exit(-1);
}
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL);
cout<<UE2.imsi;
//cout<<UE2.imsi<<"\n"<<UE2.Net;
//int sent = send(cli, (const void*)&mesg, sizeof mesg, 0);
//cout<<"Sent"<<sent<<" bytes to client :<<inet_ntoa(client.sin_addr)";
close(cli);
}
}
Client.cpp
#include <arpa/inet.h>
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
//cout<<server.sin.port;
server.sin_addr.s_addr = inet_addr(argv[1]);
//cout<<server.sin_addr.s_addr;
memset(&(server.sin_zero), '\0', 8);
if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1)
{
perror("Connect:");
exit(-1);
}
int count = 0;
while(count = 0)
{
send(sock, &UE1, sizeof(UE1), 0);
//receive = recv(sock, (void*)&mesg, sizeof mesg, NULL);
count++;
}
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
There are at least 2 problems in your code:
You cannot send objects like std::string and anything that contains it this way (formally non-POD data), you need to marshall your data. There are plenty of libraries around (like google proto buffers) or you can write your own. This topic is too wide to cover it in the answer here.
You cannot expect that you receive data from TCP stream by the same chunk you sent it, you must write code that can handle receiving data by pieces (and send it that way as well).
You should never ever write a whole struct to a file or a socket.
Always write each field separately, and read them the same way.
When doing it this way you pay some memory overhead, but it's generally a good design for performance reasons because you don't want to do a write of each value to the socket.
When sending binary data you should always take care for the following things:
Different endianness
Different padding
Differences in the bye-sizes of intrinsic types
You need some functions like the following:
virtual MESSAGE_BUFFER * GetMessageAsBinaryPtr()
{
MESSAGE_BUFFER * binaryMsg = new MESSAGE_BUFFER;
UINT8 * ptrBuffer = &(*binaryMsg)[0];
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_majorVersion);
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_minorVersion);
ptrBuffer = this->serializeUInt32(ptrBuffer, (UINT32)this->m_messageType);
ptrBuffer = this->serializeUInt64(ptrBuffer, this->m_packetID);
ptrBuffer = this->serializeDouble(ptrBuffer, this->m_timestamp);
return binaryMsg;
}
virtual void CreateFromBinary(MESSAGE_BUFFER buffer)
{
UINT8 * ptrBuffer = &buffer[0];
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_majorVersion);
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_minorVersion);
UINT32 messageType = 0;
ptrBuffer = this->deserializeUInt32FromBuffer(ptrBuffer, &messageType);
this->SetMessageType((MessageTypes)messageType);
ptrBuffer = this->deserializeUInt64FromBuffer(ptrBuffer, &this->m_packetID);
ptrBuffer = this->deserializeDoubleFromBuffer(ptrBuffer, &this->m_timestamp);
}
inline UINT8 * serializeUInt16(UINT8 * buffer, UINT16 value)
{
buffer[1] = value;
buffer[0] = value >> 8;
return buffer + 2;
}
inline UINT8 * deserializeUInt16FromBuffer(UINT8 * buffer, UINT16 * pOutput)
{
*pOutput = (*pOutput << 8) + buffer[0];
*pOutput = (*pOutput << 8) + buffer[1];
return buffer + 2;
}
When you have such functions you can serialize and deserialize your structs to a buffer and then send this buffer over your socket.
A few points to note:
The struct to send is first serialized, field by field into a buffer
MESSAGE_BUFFER is of type UINT8[1024]
The serialization routine returns a pointer to the next free byte in the buffer, which we use to compute how many bytes it serialized to
Theres no protection against buffer overflows in my routines
There are few bugs in your code.
In server.cpp
sockaddr_in --> struct sockaddr_in
Once connection request is accepted by server using accept() call, it returns new file descriptor, with that new fd you should do read and write operation not with old one.
Replace below statement
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL); /** you are receiving with old fd called sock **/
with
receive = recv(cli, (void*)&UE2, sizeof(UE2), NULL);
client.cpp
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
sock = socket(PF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
memset(&(server.sin_zero), '\0', 8);
connect(sock, (struct sockaddr*)&server, sizeof(server));
perror("Connect:");
int count = 0;
send(sock, &UE1, sizeof(UE1), 0);
perror("send");
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
server.cpp
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
int sock, cli, receive;
struct sockaddr_in server, client;
unsigned int len;
sock = socket(AF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(10001);
server.sin_addr.s_addr = INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(server);
bind(sock, (struct sockaddr *)&server, len);
perror("Bind:");
listen(sock, 1);
perror("Listen:");
cli = accept(sock,(struct sockaddr *)&client, &len);
perror("accept");
receive = recv(cli, ( void*)&UE2, sizeof(UE2), 0);
perror("recv");
cout << "rec = "<<receive<<endl;
cout<<UE2.imsi<<"\n";
close(sock);
perror("close");
}
I want extract payload from ICMP pakage, here a code from internet in linux (I'm on windows) but not work.
/*..........*/
char * data_re;
char buf[1024];
memset(buf, 0, sizeof(buf));
int nbytes = recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr *)&dest,&af);
if (nbytes < 0)
{return 0;}
if(nbytes > 0){
struct iphdr *ip;
icmph = NULL;
ip = (struct iphdr *) buf;
if (nbytes > sizeof(ip)) {
nbytes -= sizeof(ip);
icmph = (struct icmphdr *) ip + 1;
if (nbytes > sizeof(icmphdr)) {
nbytes -= sizeof(icmphdr);
data_re = (char *) (icmph + 1);
data_re[nbytes] = '\0';
printf("%s", data_re);
//fflush(stdout);
}
}
}
/*..........*/
My teacher want us to do an exercise on raw socket in c ++ on Windows (for learning tcp communication).
I have got a problem with it. I saw a lot of documentation but I don't know how to solve it.
int raw()
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN sin,din;
WSAStartup(MAKEWORD(2, 2), &WSAData);
char datagram[MAX_PACKET_SIZE];
struct iphdr *iph = (struct iphdr *)datagram;
struct tcphdr *tcph = (struct tcphdr *)((UCHAR *)iph + sizeof(tcphdr));
char new_ip[sizeof "255.255.255.255"];
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
cout << "failled init socket" << endl ;
else{
memset(datagram, 0, MAX_PACKET_SIZE); // Clear the data
setup_ip_header(iph);
setup_tcp_header(tcph);
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.s_addr = inet_addr("192.168.1.10"); //source ip
din.sin_family = AF_INET;
din.sin_port = htons(DEST_PORT);
din.sin_addr.s_addr = inet_addr(TARGET_SERV_IP); //ip serv to connect
tcph->port_dest = htons(DEST_PORT);
iph->ip_dest = din.sin_addr.s_addr;
iph->ip_source = sin.sin_addr.s_addr;
iph->ip_dest = inet_addr(TARGET_SERV_IP); //ip serv to connect
iph->ip_source = inet_addr("192.168.1.10"); //source ip
//iph->checksum = csum((unsigned short *)datagram, iph->tot_len >> 1);
iph->checksum = csum((unsigned short *)datagram, sizeof(struct iphdr));
int one = 1;
const int *val = &one;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)val, sizeof(one)) < 0)
printf("failled set socket option IP_HDRINCL");
else{
if (sendto(sock, /* our socket */
datagram, /* the buffer containing headers and data */
ntohs( iph->tot_len), /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof(sin)) < 0) /* a normal send() */
cout << stderr << "sendto() error!!!.\n " << WSAGetLastError() << endl;
else
cout << "packet send\n" << endl;
}
closesocket(sock);
}
}
My error occurs at the sendto(). it return 10022 error = WSAEINVAL
I saw that can be a new windows protection?
Have you any idea to fix my problem or bypass the protection (go deeper, driver, etc)
You don't set iph->tot_len in your code.
My recommendation for networking code using c++ would be to use std::string or std::vector:
std::vector<uint8_t> packet(MAX_PACKET_SIZE, 0);
...
packet.resize(real_size);
then use the address (&packet[0]) for your pointer manipulations.