Adding printf change sendTo result from failure to success - c

I know that it sound strange. printf shouldnt change anything,but without it sendTo failed.
The program was copied from c code and compiled by cpp compiler on ubuntux86.
I have a program to send arp request. without this printf the sendTo failed.
The strange thing is that i did a minimal program that dont use in the printf variable at all (only in the printf) and with the printf it work and without the printf it doesn’t work (get invalid argument error on the sendTo).
The attach is a minimal version only for showing the problem:
This sendTo failed:
int retVal = sendto(arp_fd, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa,sizeof(sa));
if (retVal < 0) {
perror("sendto");
close(arp_fd);
exit(1);
}
when adding this it work:
struct ifreq ifr;//There is no use except in the printf
printf("MAC address: is %02x:%02x:%02x:%02x:%02x:%02x \n",
ifr.ifr_hwaddr.sa_data[0]&0xFF,
ifr.ifr_hwaddr.sa_data[1]&0xFF,
ifr.ifr_hwaddr.sa_data[2]&0xFF,
ifr.ifr_hwaddr.sa_data[3]&0xFF,
ifr.ifr_hwaddr.sa_data[5]&0xFF,
ifr.ifr_hwaddr.sa_data[4]&0xFF);
The complete program:
#include "sys/socket.h"
#include "sys/types.h"
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "net/if.h"
#include "stdlib.h"
#include "arpa/inet.h"
#include "netinet/in.h"
#include "sys/ioctl.h"
#include "netpacket/packet.h"
#include "net/ethernet.h"
#define ETHER_TYPE_FOR_ARP 0x0806
#define HW_TYPE_FOR_ETHER 0x0001
#define OP_CODE_FOR_ARP_REQ 0x0001
#define HW_LEN_FOR_ETHER 0x06
#define HW_LEN_FOR_IP 0x04
#define PROTO_TYPE_FOR_IP 0x0800
typedef unsigned char byte1;
typedef unsigned short int byte2;
typedef unsigned long int byte4;
// For Proper memory allocation in the structure
#pragma pack(1)
typedef struct arp_packet {
// ETH Header
byte1 dest_mac[6];
byte1 src_mac[6];
byte2 ether_type;
// ARP Header
byte2 hw_type;
byte2 proto_type;
byte1 hw_size;
byte1 proto_size;
byte2 arp_opcode;
byte1 sender_mac[6];
byte4 sender_ip;
byte1 target_mac[6];
byte4 target_ip;
// Paddign
char padding[18];
} ARP_PKT;
int main() {
struct sockaddr_ll sa;
// Ethernet Header
ARP_PKT pkt;
memset(pkt.dest_mac, 0xFF, (6 * sizeof(byte1)));
memset(pkt.src_mac, 0x1, (6 * sizeof(byte1)));
pkt.ether_type = htons(ETHER_TYPE_FOR_ARP);
// ARP Header
pkt.hw_type = htons(HW_TYPE_FOR_ETHER);
pkt.proto_type = htons(PROTO_TYPE_FOR_IP);
pkt.hw_size = HW_LEN_FOR_ETHER;
pkt.proto_size = HW_LEN_FOR_IP;
pkt.arp_opcode = htons(OP_CODE_FOR_ARP_REQ);
memcpy(pkt.sender_mac, pkt.src_mac, (6 * sizeof(byte1)));
pkt.sender_ip = 2449647808;
memset(pkt.target_mac, 0, (6 * sizeof(byte1)));
pkt.target_ip = inet_addr("10.0.0.10");
// Padding
memset(pkt.padding, 0, 18 * sizeof(byte1));
sa.sll_family = AF_PACKET;
sa.sll_ifindex = 3;
sa.sll_protocol = htons(ETH_P_ARP);
/* Send it! */
int arp_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
struct ifreq ifr;
printf("MAC address: is %02x:%02x:%02x:%02x:%02x:%02x \n",
ifr.ifr_hwaddr.sa_data[0]&0xFF,
ifr.ifr_hwaddr.sa_data[1]&0xFF,
ifr.ifr_hwaddr.sa_data[2]&0xFF,
ifr.ifr_hwaddr.sa_data[3]&0xFF,
ifr.ifr_hwaddr.sa_data[5]&0xFF,
ifr.ifr_hwaddr.sa_data[4]&0xFF);
int retVal = sendto(arp_fd, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa,sizeof(sa));
if (retVal < 0) {
perror("sendto");
close(arp_fd);
exit(1);
}
printf("\n=========PACKET=========\n");
return 0;
}

This is because you have uninitialized values in struct sockaddr_ll sa. More specifically, your call to printf forces the compiler to save three registers on the stack therefore moving sa location and its values. You can printf("halen %p %d\n", &sa.sll_halen, sa.sll_halen); before your printf to see it change depending on wether you add your printf or not.
Just add sa.sll_halen = 0; to see the difference… And for your real program initialize the whole structure.

Related

how to use the ioctl() function with audio CD drives

I am trying to write a C program using the I/O call system in Ubuntu.
I found this documentation, CDROM API from Linux-sxs.org, but I don't understand where to find those arguments.
Can you please give me an example about how to use the ioctl() function?
struct cdrom_read_audio ra
{
union cdrom_addr addr; /* REQUIRED frame address */
u_char addr_format; /* REQUIRED .....CDROM_LBA or CDROM_MSF */
int nframes; /* REQUIRED number of 2352-byte-frames to read*/
u_char *buf; /* REQUIRED frame buffer (size: nframes*2352 bytes) */
};
if (ioctl(cdrom, CDROMREADAUDIO, &ra)<0)
{
perror("ioctl");
exit(1);
}
According to the kernel documentation for the cdrom driver, cdrom.txt, the format of the command is as follows:
CDROMREADAUDIO (struct cdrom_read_audio)
usage:
struct cdrom_read_audio ra;
ioctl(fd, CDROMREADAUDIO, &ra);
inputs:
cdrom_read_audio structure containing read start
point and length
outputs:
audio data, returned to buffer indicated by ra
error return:
EINVAL format not CDROM_MSF or CDROM_LBA
EINVAL nframes not in range [1 75]
ENXIO drive has no queue (probably means invalid fd)
ENOMEM out of memory
The format of the cdrom_read_audio struct can be found in cdrom.h:
/* This struct is used by the CDROMREADAUDIO ioctl */
struct cdrom_read_audio
{
union cdrom_addr addr; /* frame address */
__u8 addr_format; /* CDROM_LBA or CDROM_MSF */
int nframes; /* number of 2352-byte-frames to read at once */
__u8 __user *buf; /* frame buffer (size: nframes*2352 bytes) */
};
It uses a union cdrom_addr type, defined in the same file:
/* Address in either MSF or logical format */
union cdrom_addr
{
struct cdrom_msf0 msf;
int lba;
};
Here we have a choice - use MSF (Mintues-Seconds-Frames) or LBA (Logical Block Addressing). Since you're reading audio, you'll probably want MSF. struct cdrom_msf0 can also be found in the header file:
/* Address in MSF format */
struct cdrom_msf0
{
__u8 minute;
__u8 second;
__u8 frame;
};
With this research, we can write a simple test:
#include <sys/ioctl.h> //Provides ioctl()
#include <linux/cdrom.h> //Provides struct and #defines
#include <unistd.h> //Provides open() and close()
#include <sys/types.h> //Provides file-related #defines and functions
#include <sys/stat.h> //Ditto
#include <fcntl.h> //Ditto
#include <stdlib.h> //Provides malloc()
#include <string.h> //Provides memset()
#include <stdint.h> //Provides uint8_t, etc
#include <errno.h> //Provides errno
#include <stdio.h> //Provides printf(), fprintf()
int main()
{
int fd = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
if (errno != 0)
{
fprintf(stderr, "Error opening file: %u\n", errno);
return -1;
}
struct cdrom_msf0 time; //The start read time ...
time.minute = 2;
time.second = 45;
time.frame = 0;
union cdrom_addr address; //... in a union
address.msf = time;
struct cdrom_read_audio ra; //Our data object
ra.addr = address; //With the start time
ra.addr_format = CDROM_MSF; //We used MSF
ra.nframes = CD_FRAMES; //A second - 75 frames (the most we can read at a time anyway)
uint8_t* buff = malloc(CD_FRAMES * CD_FRAMESIZE_RAW); //Frames per second (75) * bytes per frame (2352)
memset(buff, 0, CD_FRAMES * CD_FRAMESIZE_RAW); //Make sure it's empty
ra.buf = buff; //Set our buffer in our object
if (ioctl(fd, CDROMREADAUDIO, &ra) != 0) //The ioctl call
{
fprintf(stderr, "Error giving ioctl command: %u\n", errno);
return -1;
}
for (int frame = 0; frame < CD_FRAMES; frame++) //A hexdump (could be a real use for the data)
{
printf("Frame %u:", frame);
for (int byte = 0; byte < CD_FRAMESIZE_RAW; byte++)
{
printf(" %.2X", buff[frame * CD_FRAMESIZE_RAW + byte]);
}
printf("\n");
}
close(fd); //Close our file
return 0; //And exit
}
Make sure you use an audio CD, or the ioctl call will throw EIO (with a CD-ROM, for example). In reality, you might write this data to file, or process it. Either way, you'd likely end up reading more than one second using a loop.

Writing to socket fails with the addition of any single line of code to c program

I'm writing a c program designed to transfer data over a socket to python client. I've encountered a really strange issue where writing to the created socket stops working with the addition of virtually any line of code after a certain point in the program.
To expand on the issue: I'm trying to write an arbitrary number to the socket, e.g. 256. This works fine, i.e. the python client receives the number 256 from the c server, as long as there aren't any commands beyond get_status(s2mm_status,"S2MM"); If there are any such commands beyond this point, the "0" gets written to the socket instead of whatever number (e.g. 256) I've specified. Anything as simple as the declaration "int i" results in this behavior.
Needless to say, I'm confused. I'm wondering if I'm using too much memory or something? I just don't know how to diagnose the problem. Anyway, I've provided the code below. Sorry about the length, I just really don't know what is or is not relevant.
To provide a basic explanation of the code: a number of memory maps are created so that I can write specific values to registers, which initiates the recording of data from an ADC aboard the device, writing of this data to memory, and then passing this data over a socket to the python client.
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h> // inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading, link with lpthread
#include<sys/mman.h>
#include <fcntl.h>
#include <arpa/inet.h> //https://linux.die.net/man/3/htonl
#include <time.h>
#include<math.h>
#include "server_library.h"
/*********************************/
//Address Editor
/*********************************/
//ps_0
// Data
// axi_dma_0 S_AXI_LITE reg 0x4040_0000 64K 0x4040_FFFF
//axi_dma_0
// Data_SG
// ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
// DATA_MM2S
// ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
// DATA_S2MM
// ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
/*********************************/
/*********************************/
//Addresses
/*********************************/
#define AXI_DMA_ADDRESS 0x40400000
#define HP0_ADDRESS 0x08000000 //Formerly HP0_DMA_BUFFER_MEM_ADDRESS
#define MM2S_BASE_DESC_ADDR HP0_ADDRESS //Formerly HP0_MM2S_DMA_DESCRIPTORS_ADDRESS
#define S2MM_BASE_DESC_ADDR HP0_ADDRESS+MEMBLOCK_WIDTH+1 //Formerly HP0_S2MM_DMA_DESCRIPTORS_ADDRESS
#define MM2S_SOURCE_ADDRESS HP0_ADDRESS+SG_DMA_DESCRIPTORS_WIDTH+1 //Formerly HP0_MM2S_SOURCE_MEM_ADDRESS
#define S2MM_TARGET_ADDRESS HP0_ADDRESS+(MEMBLOCK_WIDTH+1)+SG_DMA_DESCRIPTORS_WIDTH+1 //Formerly HP0_S2MM_TARGET_MEM_ADDRESS
// AXI_DMA_ADDRESS: 0x40400000
// HP0_ADDRESS: 0x08000000
// MM2S_BASE_DESC_ADDR: 0x08000000
// S2MM_BASE_DESC_ADDR: 0x0c000000
// MM2S_SOURCE_ADDRESS: 0x08010000
// S2MM_TARGET_ADDRESS: 0x0c010000
/*********************************/
//Miscellaneous
/*********************************/
#define DESCRIPTOR_REGISTERS_SIZE 0xFFFF
#define SG_DMA_DESCRIPTORS_WIDTH 0xFFFF
#define MEMBLOCK_WIDTH 0x3FFFFFF //Size of memory used by S2MM and MM2S
#define BUFFER_BLOCK_WIDTH 0x7D0000 //Size of memory block per descriptor in bytes
#define NUM_OF_DESCRIPTORS 0x02 //Number of descriptors for each direction
#define START_FRAME 0x08000000 //TXSOF = 1 TXEOF = 0
#define MID_FRAME 0x00000000 //TXSOF = TXEOF = 0
#define COMPLETE_FRAME 0x0C000000 //TXSOF = TXEOF = 1
#define END_FRAME 0x04000000 //TXSOF = 0 TXEOF = 1
#define CYCLIC_ENABLE 0x10
#define TRANSFER_BYTES 1024
#define TRANSFER_INTS 256
#define TRANSFER_BITS 8*TRANSFER_BYTES
#define N_DESC 2
/*********************************/
//Offsets
/*********************************/
// MM2S CONTROL
#define MM2S_CONTROL_REGISTER 0x00 // MM2S_DMACR
#define MM2S_STATUS_REGISTER 0x04 // MM2S_DMASR
#define MM2S_CURDESC 0x08 // must align 0x40 addresses
#define MM2S_CURDESC_MSB 0x0C // unused with 32bit addresses
#define MM2S_TAILDESC 0x10 // must align 0x40 addresses
#define MM2S_TAILDESC_MSB 0x14 // unused with 32bit addresses
#define SG_CTL 0x2C // CACHE CONTROL
// S2MM CONTROL
#define S2MM_CONTROL_REGISTER 0x30 // S2MM_DMACR
#define S2MM_STATUS_REGISTER 0x34 // S2MM_DMASR
#define S2MM_CURDESC 0x38 // must align 0x40 addresses
#define S2MM_CURDESC_MSB 0x3C // unused with 32bit addresses
#define S2MM_TAILDESC 0x40 // must align 0x40 addresses
#define S2MM_TAILDESC_MSB 0x44 // unused with 32bit addresses
//Scatter/Gather Control
#define NEXT_DESC 0x00 //Set to address of next descriptor in chain
#define BUFF_ADDR 0x08 //Set to address to read from (MM2S) or write to (S2MM)
#define CONTROL 0x18 //Set transfer length, T/RXSOF and T/RXEOF
#define STATUS 0x1C //Descriptor status
/*********************************/
//Functions
/*********************************/
unsigned int set_offset(unsigned int* virtual_address, int offset, unsigned int value){
virtual_address[offset>>2] = value;
}
unsigned int get_offset(unsigned int* virtual_address, int offset) {
return virtual_address[offset>>2];
}
void print_offset(unsigned int* virtual_address, int offset){
unsigned int value = get_offset(virtual_address,offset);
printf("0x%08x\n",value);
}
void memsend(void* virtual_address, int byte_count, int socket_desc)
{
unsigned int *p = virtual_address;
int offset;
for(offset = 0; offset<byte_count;offset++){
printf("0x%08x\n",p[offset]);
write(socket_desc,&p[offset],sizeof(p[offset]));
}
}
void memdump(void* virtual_address, int byte_count)
{
unsigned int *p = virtual_address;
int offset;
for(offset = 0; offset<byte_count;offset++){
printf("%d: 0x%08x\n",offset,p[offset]);
}
}
void get_status(uint32_t status, char *type){
if(type == "S2MM"){
printf("S2MM status 0x%08x #0x%08x\n",status,AXI_DMA_ADDRESS+S2MM_STATUS_REGISTER);
}
if(type == "MM2S"){
printf("MM2S status 0x%08x #0x%08x\n",status,AXI_DMA_ADDRESS+MM2S_STATUS_REGISTER);
}
if(status & 0x00000001) printf(" Halted");
if(status & 0x00000002) printf(" Idle");
if(status & 0x00000008) printf(" SGIncld");
if(status & 0x00000010) printf(" DMAIntErr");
if(status & 0x00000020) printf(" DMASlvErr");
if(status & 0x00000040) printf(" DMADecErr");
if(status & 0x00000100) printf(" SGIntErr");
if(status & 0x00000200) printf(" SGSlvErr");
if(status & 0x00000400) printf(" SGDecErr");
if(status & 0x00001000) printf(" IOC_Irq");
if(status & 0x00002000) printf(" Dly_Irq");
if(status & 0x00004000) printf(" Err_Irq");
else printf(" running");
printf("\n");
}
int main(){
int mm2s_status, s2mm_status;
uint32_t mm2s_base_descriptor_address; //Formerly mm2s_current_descriptor_address
uint32_t s2mm_base_descriptor_address; //Formerly s2mm_current_descriptor_address
uint32_t mm2s_tail_descriptor_address;
uint32_t s2mm_tail_descriptor_address;
int fd = open("/dev/mem",O_RDWR|O_SYNC);
//Create 64K AXI DMA Memory Map at AXI_DMA_ADDRESS (0x40400000)
unsigned int* axi_dma = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,AXI_DMA_ADDRESS);
//Create 64k mm2s descriptors memory map at HP0_MM2S_DMA_DESCRIPTORS_ADDRESS (0x08000000)
unsigned int* mm2s_descriptors = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,MM2S_BASE_DESC_ADDR); //Formerly mm2s_descriptor_register_mmap
//Create 64k s2mm descriptors memory map at HP0_S2MM_DMA_DESCRIPTORS_ADDRESS (0x0c000000)
unsigned int* s2mm_descriptors = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,S2MM_BASE_DESC_ADDR); //Formerly s2mm_descriptor_register_mmap
//Create ~1Mb x Num_Descriptors source memory map at HP0_MM2S_SOURCE_MEM_ADDRESS (0x08010000)
unsigned int* source_memory = mmap(NULL,BUFFER_BLOCK_WIDTH*NUM_OF_DESCRIPTORS,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)(MM2S_SOURCE_ADDRESS)); //Formerly source_mmap
//Create ~1Mb x Num_Descriptors target memory map at HP0_S2MM_TARGET_MEM_ADDRESS (0x0c010000)
unsigned int* dest_memory = mmap(NULL,BUFFER_BLOCK_WIDTH*NUM_OF_DESCRIPTORS,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)(S2MM_TARGET_ADDRESS)); //Formerly dest_mmap
//Clear mm2s descriptors
memset(mm2s_descriptors,0x00000000,DESCRIPTOR_REGISTERS_SIZE);
//Clear s2mm descriptors
memset(s2mm_descriptors,0x00000000,DESCRIPTOR_REGISTERS_SIZE);
//Clear Target Memory
memset(dest_memory,0x00000000,NUM_OF_DESCRIPTORS*BUFFER_BLOCK_WIDTH/4);
//Reset and halt all DMA operations
set_offset(axi_dma,MM2S_CONTROL_REGISTER,0x4);
set_offset(axi_dma,S2MM_CONTROL_REGISTER,0x4);
set_offset(axi_dma,MM2S_CONTROL_REGISTER,0x0);
set_offset(axi_dma,S2MM_CONTROL_REGISTER,0x0);
mm2s_status = get_offset(axi_dma,MM2S_STATUS_REGISTER);
s2mm_status = get_offset(axi_dma,S2MM_STATUS_REGISTER);
get_status(mm2s_status,"MM2S");
get_status(s2mm_status,"S2MM");
/*********************************************************************/
// Any code after this point, save for a print function,
// breaks the write function (line 223) below.
//Specifically, it goes from correctly writing TRANSFER_INTS = 256
//to writing 0 to "new_socket"
//????
/*********************************************************************/
/*********************************************************************/
// Open a server
/*********************************************************************/
//Define variables
int new_socket,c;
int socket_desc;
struct sockaddr_in created_server_addr, client_addr;
//Create Socket
socket_desc = open_socket(socket_desc);
//Create Server
created_server_addr = server_structure(created_server_addr);
//Bind Socket
bind_socket(socket_desc,created_server_addr);
//Listen
listen(socket_desc,3);
puts("Waiting for incoming connections...");
//Transfer Data over socket
while(new_socket=accept(socket_desc,(struct sockaddr *)&client_addr, (socklen_t*)&c))
{
puts("Connection Accepted.\n");
printf("Transfer Size: %d\n",TRANSFER_INTS);
uint32_t htonl_TRANSFER_INTS = htonl(TRANSFER_INTS);
write(new_socket, &htonl_TRANSFER_INTS,sizeof(htonl_TRANSFER_INTS));
printf("Write Data (Destination memory block): \n");
close(new_socket);
break;
}
close(socket_desc);
/*********************************************************************/
}
I'm also including the "server_library.h" file for reference, which I wrote ti simplify the process of starting a socket a little bit. I can provide the python client code on request, but I'm already worried this is way too much code to sift through already.
#ifndef MY_HEADER_H
#define MY_HEADER_H
//Start/open Socket
int open_socket(int socket_desc)
{
int option = 1;
socket_desc = socket(AF_INET,SOCK_STREAM,0);
if(socket_desc == -1)
{
printf("Could not create socket\n");
}
//This stupid line fixes binds failing
setsockopt(socket_desc,SOL_SOCKET,SO_REUSEADDR,(void *)&option,sizeof(option));
return socket_desc;
}
//Prepare server structure
struct sockaddr_in server_structure(struct sockaddr_in server_addr)
{
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8888);
return server_addr;
}
//Bind Socket
void bind_socket(int socket_desc, struct sockaddr_in server_addr)
{
if(bind(socket_desc,(struct sockaddr *)&server_addr, sizeof(server_addr))<0)
{
puts("Bind Failed\n");
}else{
puts("Bind Done\n");
}
}
//Send Message (uint32_t)
//Doesn't Work I dunno why
void send_int(uint32_t message, int socket)
{
message = htonl(message);
write(socket, &message, sizeof(message));
}
#endif
I'm sorry to be so vague here and throw so much code out, I just don't even really have any ideas for how to diagnose this issue, let alone start narrowing the cause down.
Anyway, thank you for the help. I'm happy to provide as much additional information as I am able.
When changing the code in unrelated ways breaks a program, here are some things to check for:
1. Stack overflow (this is more common in firmware/embedded code on microprocessors, but can happen especially with recursion or if you put large arrays and such on the stack)
2. Wild pointers, out-of-bounds writes to arrays or strings, etc. which lead to a memory overwrite (changing the code in an unrelated way may change the memory layout such that the memory overwrite is in either a harmless or a harmful location) [Do you check that all the arrays you try to allocate are successfully allocated?] [uses of set_offset are candidates for out-of-bounds access]
That is where I would start.
And, of course, turning on compiler warnings and checking return values from all function calls that have them.
If you do all of the above, you will either find the bug, or you can give us information which will help us to help you better.

GCC won't compile program

Alright, so I'm going crazy over this one. I'm currently trying to go through Hacking: Art of Exploitation and I'm on the part about socket programming. So here is the code and the compiler output below it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "hacking.h"
#define PORT 7890 // the port users will be connecting to
int main(void) {
int sockfd, new_sockfd; // listen on sock_fd, new connection on new_fd
struct sockaddr_in host_addr, client_addr; // my address information
socklen_t sin_size;
int recv_length=1, yes=1;
char buffer[1024];
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
fatal("in socket");
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
fatal("setting socket option SO_REUSEADDR");
host_addr.sin_family = AF_INET; // host byte order
host_addr.sin_port = htons(PORT); // short, network byte order
host_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(host_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)) == -1)
fatal("binding to socket");
if (listen(sockfd, 5) == -1)
fatal("listening on socket");
while(1) { // Accept loop
sin_size = sizeof(struct sockaddr_in);
new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
if(new_sockfd == -1)
fatal("accepting connection");
printf("server: got connection from %s port %d\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
send(new_sockfd, "Hello World!\n", 13, 0);
recv_length = recv(new_sockfd, &buffer, 1024, 0);
while(recv_length > 0) {
printf("RECV: %d bytes\n", recv_length);
dump(buffer, recv_length);
recv_length = recv(new_sockfd, &buffer, 1024, 0);
}
close(new_sockfd);
}
return 0;
}
Compiler output:
root#root-laptop:~ $ gcc simple_server.c
In file included from /usr/include/sys/socket.h:35,
from simple_server.c:7:
/usr/include/bits/socket.h:122: error: syntax error before "define"
In file included from /usr/include/sys/socket.h:35,
from simple_server.c:7:
/usr/include/bits/socket.h:147: error: syntax error before "sa_family_t"
/usr/include/bits/socket.h:149: error: syntax error before '}' token
/usr/include/bits/socket.h:164: error: syntax error before "sa_family_t"
/usr/include/bits/socket.h:167: error: syntax error before '}' token
In file included from simple_server.c:9:
/usr/include/netinet/in.h:221: error: syntax error before "sa_family_t"
/usr/include/netinet/in.h:226: error: invalid application of `sizeof' to an incomplete type
/usr/include/netinet/in.h:229: error: size of array `sin_zero' is too large
/usr/include/netinet/in.h:230: error: syntax error before '}' token
/usr/include/netinet/in.h:235: error: syntax error before "sa_family_t"
/usr/include/netinet/in.h:240: error: syntax error before '}' token
/usr/include/netinet/in.h:283: error: field `gr_group' has incomplete type
/usr/include/netinet/in.h:292: error: field `gsr_group' has incomplete type
/usr/include/netinet/in.h:295: error: field `gsr_source' has incomplete type
/usr/include/netinet/in.h:327: error: field `gf_group' has incomplete type
/usr/include/netinet/in.h:335: error: field `gf_slist' has incomplete type
In file included from simple_server.c:9:
/usr/include/netinet/in.h:465: error: field `ip6m_addr' has incomplete type
simple_server.c: In function `main':
simple_server.c:17: error: storage size of `host_addr' isn't known
simple_server.c:17: error: storage size of `client_addr' isn't known
simple_server.c:34: error: invalid application of `sizeof' to an incomplete type
simple_server.c:41: error: invalid application of `sizeof' to an incomplete type
simple_server.c: At top level:
/usr/include/netinet/in.h:229: error: storage size of `sin_zero' isn't known
For some reason GCC isn't finding the predefined struct in the header files. I've tried everything to fix this, from removing header files to adding only certain ones.
Also I should note that I'm using the VM image that came with the book. It's an old version of Ubuntu and GCC.
Edit:
Here are the requested files.
socket.h
#ifndef __BITS_SOCKET_H
#define __BITS_SOCKET_H
#if !defined _SYS_SOCKET_H && !defined _NETINET_IN_H
# error "Never include <bits/socket.h> directly; use <sys/socket.h> instead."
#endif
#define __need_size_t
#define __need_NULL
#include <stddef.h>
#include <limits.h>
#include <sys/types.h>
/* Type for length arguments in socket calls. */
#ifndef __socklen_t_defined
typedef __socklen_t socklen_t;
# define __socklen_t_defined
#endif
/* Types of sockets. */
enum __socket_type
{
SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
byte streams. */
#define SOCK_STREAM SOCK_STREAM
SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams
of fixed maximum length. */
#define SOCK_DGRAM SOCK_DGRAM
SOCK_RAW = 3, /* Raw protocol interface. */
#define SOCK_RAW SOCK_RAW
SOCK_RDM = 4, /* Reliably-delivered messages. */
#define SOCK_RDM SOCK_RDM
SOCK_SEQPACKET = 5, /* Sequenced, reliable, connection-based,
datagrams of fixed maximum length. */
#define SOCK_SEQPACKET SOCK_SEQPACKET
SOCK_PACKET = 10 /* Linux specific way of getting packets
at the dev level. For writing rarp and
other similar things on the user level. */
#define SOCK_PACKET SOCK_PACKET
};
/* Protocol families. */
#define PF_UNSPEC 0 /* Unspecified. */
#define PF_LOCAL 1 /* Local to host (pipes and file-domain). */
#define PF_UNIX PF_LOCAL /* Old BSD name for PF_LOCAL. */
#define PF_FILE PF_LOCAL /* Another non-standard name for PF_LOCAL. */
#define PF_INET 2 /* IP protocol family. */
#define PF_AX25 3 /* Amateur Radio AX.25. */
#define PF_IPX 4 /* Novell Internet Protocol. */
#define PF_APPLETALK 5 /* Appletalk DDP. */
#define PF_NETROM 6 /* Amateur radio NetROM. */
#define PF_BRIDGE 7 /* Multiprotocol bridge. */
#define PF_ATMPVC 8 /* ATM PVCs. */
#define PF_X25 9 /* Reserved for X.25 project. */
#define PF_INET6 10 /* IP version 6. */
#define PF_ROSE 11 /* Amateur Radio X.25 PLP. */
#define PF_DECnet 12 /* Reserved for DECnet project. */
#define PF_NETBEUI 13 /* Reserved for 802.2LLC project. */
#define PF_SECURITY 14 /* Security callback pseudo AF. */
#define PF_KEY 15 /* PF_KEY key management API. */
#define PF_NETLINK 16
#define PF_ROUTE PF_NETLINK /* Alias to emulate 4.4BSD. */
#define PF_PACKET 17 /* Packet family. */
#define PF_ASH 18 /* Ash. */
#define PF_ECONET 19 /* Acorn Econet. */
#define PF_ATMSVC 20 /* ATM SVCs. */
#define PF_SNA 22 /* Linux SNA Project */
#define PF_IRDA 23 /* IRDA sockets. */
#define PF_PPPOX 24 /* PPPoX sockets. */
#define PF_WANPIPE 25 /* Wanpipe API sockets. */
#define PF_BLUETOOTH 31 /* Bluetooth sockets. */
#define PF_MAX 32 /* For now.. */
/* Address families. */
#define AF_UNSPEC PF_UNSPEC
#define AF_LOCAL PF_LOCAL
#define AF_UNIX PF_UNIX
#define AF_FILE PF_FILE
#define AF_INET PF_INET
#define AF_AX25 PF_AX25
#define AF_IPX PF_IPX
#define AF_APPLETALK PF_APPLETALK
#define AF_NETROM PF_NETROM
#define AF_BRIDGE PF_BRIDGE
#define AF_ATMPVC PF_ATMPVC
#define AF_X25 PF_X25
#define AF_INET6 PF_INET6
#define AF_ROSE PF_ROSE
#define AF_DECnet PF_DECnet
#define AF_NETBEUI PF_NETBEUI
#define AF_SECURITY PF_SECURITY
#define AF_KEY PF_KEY
#define AF_NETLINK PF_NETLINK
#define AF_ROUTE PF_ROUTE
#define AF_PACKET PF_PACKET
#define AF_ASH PF_ASH
#define AF_ECONET PF_ECONET
#define AF_ATMSVC PF_ATMSVC
#define AF_SNA PF_SNA
#define AF_IRDA PF_IRDA
#define AF_PPPOX PF_PPPOX
o define AF_WANPIPE PF_WANPIPE
#define AF_BLUETOOTH PF_BLUETOOTH
#define AF_MAX PF_MAX
/* Socket level values. Others are defined in the appropriate headers.
XXX These definitions also should go into the appropriate headers as
far as they are available. */
#define SOL_RAW 255
#define SOL_DECNET 261
#define SOL_X25 262
#define SOL_PACKET 263
#define SOL_ATM 264 /* ATM layer (cell level). */
#define SOL_AAL 265 /* ATM Adaption Layer (packet level). */
#define SOL_IRDA 266
/* Maximum queue length specifiable by listen. */
#define SOMAXCONN 128
/* Get the definition of the macro to define the common sockaddr members. */
#include <bits/sockaddr.h>
/* Structure describing a generic socket address. */
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
/* Structure large enough to hold any socket address (with the historical
exception of AF_UNIX). We reserve 128 bytes. */
#if ULONG_MAX > 0xffffffff
# define __ss_aligntype __uint64_t
#else
# define __ss_aligntype __uint32_t
#endif
#define _SS_SIZE 128
#define _SS_PADSIZE (_SS_SIZE - (2 * sizeof (__ss_aligntype)))
struct sockaddr_storage
{
__SOCKADDR_COMMON (ss_); /* Address family, etc. */
__ss_aligntype __ss_align; /* Force desired alignment. */
char __ss_padding[_SS_PADSIZE];
};
/* Bits in the FLAGS argument to `send', `recv', et al. */
enum
{
MSG_OOB = 0x01, /* Process out-of-band data. */
#define MSG_OOB MSG_OOB
MSG_PEEK = 0x02, /* Peek at incoming messages. */
#define MSG_PEEK MSG_PEEK
MSG_DONTROUTE = 0x04, /* Don't use local routing. */
#define MSG_DONTROUTE MSG_DONTROUTE
#ifdef __USE_GNU
/* DECnet uses a different name. */
MSG_TRYHARD = MSG_DONTROUTE,
# define MSG_TRYHARD MSG_DONTROUTE
#endif
MSG_CTRUNC = 0x08, /* Control data lost before delivery. */
#define MSG_CTRUNC MSG_CTRUNC
MSG_PROXY = 0x10, /* Supply or ask second address. */
#define MSG_PROXY MSG_PROXY
MSG_TRUNC = 0x20,
#define MSG_TRUNC MSG_TRUNC
MSG_DONTWAIT = 0x40, /* Nonblocking IO. */
#define MSG_DONTWAIT MSG_DONTWAIT
MSG_EOR = 0x80, /* End of record. */
#define MSG_EOR MSG_EOR
MSG_WAITALL = 0x100, /* Wait for a full request. */
#define MSG_WAITALL MSG_WAITALL
MSG_FIN = 0x200,
#define MSG_FIN MSG_FIN
MSG_SYN = 0x400,
#define MSG_SYN MSG_SYN
MSG_CONFIRM = 0x800, /* Confirm path validity. */
#define MSG_CONFIRM MSG_CONFIRM
MSG_RST = 0x1000,
#define MSG_RST MSG_RST
MSG_ERRQUEUE = 0x2000, /* Fetch message from error queue. */
#define MSG_ERRQUEUE MSG_ERRQUEUE
MSG_NOSIGNAL = 0x4000, /* Do not generate SIGPIPE. */
#define MSG_NOSIGNAL MSG_NOSIGNAL
MSG_MORE = 0x8000 /* Sender will send more. */
#define MSG_MORE MSG_MORE
};
/* Structure describing messages sent by
`sendmsg' and received by `recvmsg'. */
struct msghdr
{
void *msg_name; /* Address to send to/receive from. */
socklen_t msg_namelen; /* Length of address data. */
struct iovec *msg_iov; /* Vector of data to send/receive into. */
size_t msg_iovlen; /* Number of elements in the vector. */
void *msg_control; /* Ancillary data (eg BSD filedesc passing). */
size_t msg_controllen; /* Ancillary data buffer length.
!! The type should be socklen_t but the
definition of the kernel is incompatible
with this. */
int msg_flags; /* Flags on received message. */
};
/* Structure used for storage of ancillary data object information. */
struct cmsghdr
{
size_t cmsg_len; /* Length of data in cmsg_data plus length
of cmsghdr structure.
!! The type should be socklen_t but the
definition of the kernel is incompatible
with this. */
int cmsg_level; /* Originating protocol. */
int cmsg_type; /* Protocol specific type. */
#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
__extension__ unsigned char __cmsg_data __flexarr; /* Ancillary data. */
#endif
};
/* Ancillary data object manipulation macros. */
#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
# define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data)
#else
# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1))
#endif
#define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg)
#define CMSG_FIRSTHDR(mhdr) \
((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) \
? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL)
#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
& (size_t) ~(sizeof (size_t) - 1))
#define CMSG_SPACE(len) (CMSG_ALIGN (len) \
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
struct cmsghdr *__cmsg) __THROW;
#ifdef __USE_EXTERN_INLINES
# ifndef _EXTERN_INLINE
# define _EXTERN_INLINE extern __inline
# endif
_EXTERN_INLINE struct cmsghdr *
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
{
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
/* The kernel header does this so there may be a reason. */
return 0;
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ CMSG_ALIGN (__cmsg->cmsg_len));
if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+ __mhdr->msg_controllen)
|| ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
> ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
/* No more entries. */
return 0;
return __cmsg;
}
#endif /* Use `extern inline'. */
/* Socket level message types. This must match the definitions in
<linux/socket.h>. */
enum
{
SCM_RIGHTS = 0x01 /* Transfer file descriptors. */
#define SCM_RIGHTS SCM_RIGHTS
#ifdef __USE_BSD
, SCM_CREDENTIALS = 0x02 /* Credentials passing. */
# define SCM_CREDENTIALS SCM_CREDENTIALS
#endif
};
/* User visible structure for SCM_CREDENTIALS message */
struct ucred
{
pid_t pid; /* PID of sending process. */
uid_t uid; /* UID of sending process. */
gid_t gid; /* GID of sending process. */
};
/* Get socket manipulation related informations from kernel headers. */
#include <asm/socket.h>
/* Structure used to manipulate the SO_LINGER option. */
struct linger
{
int l_onoff; /* Nonzero to linger on close. */
int l_linger; /* Time to linger. */
};
#endif /* bits/socket.h */
hacking.h
#include <stdlib.h>
//This function is used to display packet data by the server program.
void dump(const unsigned char *data_buffer, const unsigned int length){
unsigned char byte;
unsigned int i, j;
for(i = 0; i < length; i++){
byte = data_buffer[i];
printf("%02x ", data_buffer[i]); //Display byte in hex
if((( i % 16) == 15 ) || ( i == length - 1)) {
for( j = 0; j < 15 - ( i % 16 ); j++ )
printf(" ");
printf("| ");
for(j = ( i - ( i % 16 )); j <= i; j++) { //Display printable bytes from line.
byte = data_buffer[j];
if((byte > 31) && (byte < 127))//Outside printable char range
printf("%c", byte);
else
printf(".");
}
printf("\n"); // End of the dump line (each line is 16 bytes)
}//End if
}//End for
}
void fatal(char *message){
char error_message[100];
strcpy(error_message, "[!!] Fatal Error");
strncat(error_message, message, 83);
perror(error_message);
exit(-1);
}
void *ec_malloc(unsigned int size){
void *ptr;
ptr = malloc(size);
if(ptr== NULL)
fatal("in ec_malloc() on memory allocation");
return ptr;
}
in.h
https://pastebin.com/RTjSdA2e
Ok. So the problem was in socket.h. Basically this line
o define AF_WANPIPE PF_WANPIPE
needed to be changed to this
#define AF_WANPIPE PF_WANPIPE
Thanks David Wohlferd.
the contents of the hacking.h header file are not correct.
The contents should be the 'prototypes' for those functions and the actual functions should be in a separate .c file, probably named hacking.c
I.E. the contents of the hacking.h file should be:
#ifndef HACKING_H
#define HACKING_H
//This function is used to display packet data by the server program.
void dump(const unsigned char *data_buffer, const unsigned int length);
void fatal(char *message);
void *ec_malloc(unsigned int size);
#endif // HACKING_H
Notice the 'include only once' wrapper; consisting of the #ifndef, #define, and the trailing #endif statements
notice the file only contains the prototypes (it could also contain any other #define statements and/or data definitions and/or macro definitions, although in this case there are none.)
Then there should be a separate file hacking.c that contains the actual functions (and a statement: #include "hacking.h")
in general, neither function bodies nor data declarations should be in a header file. (later on, you will learn of certain exceptions to this statement, like when declaring inline functions

I am not able to set MTU size of particular interfaces(eth0 or eth1) through Netlink sockets via NETLINK_ROUTE option

I have written a program to set the MTU size of the particular interface(say eth0 or eth1) to 1100. And the Request message is send from user space using Netlink sockets via NETLINK_ROUTE option.
The message is sent successfully from user space, but when i verified the ifconfig eth0, the MTU size still shows the old value (1500). Am I verifying correctly? And how do I know the kernel is setting the MTU size correctly or not? Please find my program below and correct me if i am wrong.
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdbool.h>
struct {
struct nlmsghdr nh;
struct ifinfomsg ifinfo;
char data[100];
}req;
int ret;
struct rtattr *rta;
/* MTU Set */
unsigned int mtu = 1100;
/* rtNetlinkSockFd */
int rtNetlinkSockFd = -1;
int main()
{
int ret;
rtNetlinkSockFd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if(rtNetlinkSockFd < 0)
{
printf("Creation of NetLink Socket is failed \n");
return -1;
}
/* Memset the Requested Structure */
memset( &req, 0x00, sizeof(req));
/* Populate the Netlink Header Fields */
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
/* Link Layer: RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK, RTM_SETLINK */
req.nh.nlmsg_type = RTM_SETLINK;
/* NLM_F_REQUEST Must be set on all request messages. */
req.nh.nlmsg_flags = NLM_F_REQUEST;
req.nh.nlmsg_seq = 0;
req.nh.nlmsg_pid = 0; //getpid();
/* Populate the Ifinfo Structure Attributes */
req.ifinfo.ifi_family = AF_UNSPEC;
/* Give the Interface Name and get the Index */
req.ifinfo.ifi_index = if_nametoindex("eth0");
printf(" The NetLink Ifi_index :%d\n", req.ifinfo.ifi_index);
/* ifi_change is reserved for future use and
* should be always set to 0xFFFFFFFF. */
req.ifinfo.ifi_change = 0xFFFFFFFF;
req.ifinfo.ifi_type = 0;
req.ifinfo.ifi_flags = 0;
/* RTA is Pointed to (req+32) it means points to the DATA */
rta = (struct rtattr *)(((char *) &req) + NLMSG_ALIGN(req.nh.nlmsg_len));
/* IFLA_MTU unsigned int MTU of the device. */
rta->rta_type = IFLA_MTU;
/* Len Attribute */
rta->rta_len = sizeof(unsigned int);
req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_LENGTH(sizeof(mtu));
memcpy(RTA_DATA(rta), &mtu, sizeof(mtu));
ret = send(rtNetlinkSockFd, &req, req.nh.nlmsg_len, 0);
if (ret < 0)
{
printf( "netlink: Sending failed: (assume operstate is not supported)");
}
else
{
printf( "netlink: Sent successfully");
}
return 0;
}
I think you need to write:
rta->rta_len = RTA_LENGTH(sizeof(unsigned int));
instead of:
rta->rta_len = sizeof(unsigned int);
Use RTM_NEWLINK instead of RTM_SETLINK.
req.nh.nlmsg_type = RTM_NEWLINK;
See the manpage example.

How to append data on a packet from kernel space?

I am trying to append some data on a packet from kernel space. I have an echo client and server. I type in the command line like: ./client "message" and the server just echoes it back. The server was run with ./server .
Now, the client and server are on two different machines (may be VMs). I am writing a kernel module which runs on the client machine. Its work is to append "12345" after "message" while the packet goes out of the machine. I am presenting the code below.
/*
* This is ibss_obsf_cat.c
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/udp.h>
#include <linux/ip.h>
#undef __KERNEL__
#include <linux/netfilter_ipv4.h>
#define __KERNEL__
/*
* Function prototypes ...
*/
static unsigned int cat_obsf_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
static void hex_dump (char str[], int len)
{
}
/*
* struct nf_hook_ops instance initialization
*/
static struct nf_hook_ops cat_obsf_ops __read_mostly = {
.pf = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_IP_POST_ROUTING,
.hook = cat_obsf_begin,
};
/*
* Module init and exit functions.
* No need to worry about that.
*/
static int __init cat_obsf_init (void)
{
printk(KERN_ALERT "cat_obsf module started...\n");
return nf_register_hook(&cat_obsf_ops);
}
static void __exit cat_obsf_exit (void)
{
nf_unregister_hook(&cat_obsf_ops);
printk(KERN_ALERT "cat_obsf module stopped...\n");
}
/*
* Modification of the code begins here.
* Here are all the functions and other things.
*/
static unsigned int cat_obsf_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
unsigned char dt[] = "12345";
unsigned char *tmp;
unsigned char *ptr;
int i, j, len;
if (skb){
iph = ip_hdr(skb);
if (iph && iph->protocol && (iph->protocol == IPPROTO_UDP)){
udph = (struct udphdr *) ((__u32 *)iph + iph->ihl);
data = (char *)udph + 8;
if(ntohs(udph->dest) == 6000){
for (i=0; data[i]; i++);
len = i;
//printk(KERN_ALERT "\nData length without skb: %d", len);
//printk(KERN_ALERT "Data is: %s", data);
//printk(KERN_ALERT "dt size: %lu", sizeof(dt));
//printk(KERN_ALERT "skb->len: %d", skb->len);
tmp = kmalloc(200*sizeof(char), GFP_KERNEL);
memcpy(tmp, data, len);
ptr = tmp + len;
memcpy(ptr, dt, sizeof(dt));
printk(KERN_ALERT "tmp: %s", tmp);
printk(KERN_ALERT "skb->tail: %d", skb->tail);
//skb_put(skb, sizeof(dt));
printk(KERN_ALERT "skb->end: %d", skb->end);
printk(KERN_ALERT "skb->tail: %d", skb->tail);
printk(KERN_ALERT "skb->tail(int): %d", (unsigned int)skb->tail);
//memset(data, 0, len + sizeof(dt));
//memcpy(data, tmp, len + sizeof(dt));
//skb_add_data(skb, tmp, len+sizeof(dt));
printk(KERN_ALERT "Now data is: %s", data);
for(i=0; data[i]; i++);
printk(KERN_ALERT "data length: %d", i);
kfree(tmp);
}
}
}
return NF_ACCEPT;
}
/*
* Nothing to be touched hereafter
*/
module_init(cat_obsf_init);
module_exit(cat_obsf_exit);
MODULE_AUTHOR("Rifat");
MODULE_DESCRIPTION("Module for packet mangling");
MODULE_LICENSE("GPL");
I want to get the "message" to be "message12345" while sending out of the client machine from kernel space. So that the server will get "message12345" and echo it back, and the client will the read just "message12345" But I am having trouble with skb_put() and skb_add_data() functions. I do not understand what error was made by me. If anyone can help me with the code, I will be highly grateful. Thanks in advance. I am also giving the Makefile for convenience. This is for the distribution kernel, not for a built kernel.
#If KERNELRELEASE is defined, we've been invoked from the
#kernel build system and use its language
ifneq ($(KERNELRELEASE),)
obj-m := ibss_obsf_cat.o
#Otherwise we were called directly from the command
#line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
Now I am quite convinced that
skb->end - skb->tail
is so small that I will have to create new packets in kernel space. I have used
alloc_skb()
skb_reserve()
skb_header_pointer()
and other useful skb functions for creating a new skb, but the thing I am running out of idea is that how to route the newly created packet in the packet flowing path. How to use
ip_route_me_harder()
I looked in the xtables-addons package for suggestion, but the function they used is different from the one in linux kernel. Any suggestion is welcomed.
About one year ago for kernel 2.6.26 I did it like this:
// Do we need extra space?
if(len - skb_tailroom(skb) > 0){
// Expand skb tail until we have enough room for the extra data
if (pskb_expand_head(skb, 0, extra_data_len - skb_tailroom(skb), GFP_ATOMIC)) {
// allocation failed. Do whatever you need to do
}
// Allocation succeeded
// Reserve space in skb and return the starting point
your_favourite_structure* ptr = (your_favourite_structure*)
skb_push(skb, sizeof(*ptr));
// Now either set each field of your structure or memcpy into it.
// Remember you can use a char*
}
Don't forget:
Recalculate UDP checksum, because you changed data in the transported data.
Change the field tot_len(total length) in the ip header, because you added data to the packet.
Recalculate the IP header checksum, because you changed the tot_len field.
Extra note:
This is just a simple thing. I see in your code you're allocating tmp as a 200 byte array and using that to store the data of your message. If you send a bigger packet you'll have a hard time debugging this as kernel crashes due to memory overflows are too painful.
I have solved the problem. It was trivial. And all I am going to do is to post my code for future references and discussion.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/route.h>
#undef __KERNEL__
#include <linux/netfilter_ipv4.h>
#define __KERNEL__
#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28
static unsigned int pkt_mangle_begin(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
static struct nf_hook_ops pkt_mangle_ops __read_mostly = {
.pf = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_IP_LOCAL_OUT,
.hook = pkt_mangle_begin,
};
static int __init pkt_mangle_init(void)
{
printk(KERN_ALERT "\npkt_mangle module started ...");
return nf_register_hook(&pkt_mangle_ops);
}
static void __exit pkt_mangle_exit(void)
{
nf_unregister_hook(&pkt_mangle_ops);
printk(KERN_ALERT "pkt_mangle module stopped ...");
}
static unsigned int pkt_mangle_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
unsigned int data_len;
unsigned char extra_data[] = "12345";
unsigned char *temp;
unsigned int extra_data_len;
unsigned int tot_data_len;
unsigned int i;
__u16 dst_port, src_port;
if (skb) {
iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL);
if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) {
udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL);
src_port = ntohs (udph->source);
dst_port = ntohs (udph->dest);
if (src_port == 6000) {
printk(KERN_ALERT "UDP packet goes out");
data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
data_len = skb->len - TOT_HDR_LEN;
temp = kmalloc(512 * sizeof(char), GFP_ATOMIC);
memcpy(temp, data, data_len);
unsigned char *ptr = temp + data_len - 1;
extra_data_len = sizeof(extra_data);
memcpy(ptr, extra_data, extra_data_len);
tot_data_len = data_len + extra_data_len - 1;
skb_put(skb, extra_data_len - 1);
memcpy(data, temp, tot_data_len);
/* Manipulating necessary header fields */
iph->tot_len = htons(tot_data_len + TOT_HDR_LEN);
udph->len = htons(tot_data_len + UDP_HDR_LEN);
/* Calculation of IP header checksum */
iph->check = 0;
ip_send_check (iph);
/* Calculation of UDP checksum */
udph->check = 0;
int offset = skb_transport_offset(skb);
int len = skb->len - offset;
udph->check = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_UDP, 0);
}
}
}
return NF_ACCEPT;
}
module_init(pkt_mangle_init);
module_exit(pkt_mangle_exit);
MODULE_AUTHOR("Rifat Rahman Ovi: <rifatrahmanovi#gmail.com>");
MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in Kernel Space");
MODULE_LICENSE("GPL");
Here the thing is that, I forgot to update the length fields and forgot to update the checksum. Now, if I present the code correctly here, all should go well. There are some
other helper functions which are not included here.

Resources