Related
I want to build a tcp package in a kernel module and send it to another host by IP address using function dev_queue_xmit(skb). But I don't want to fill the Mac address manually by hand. The following is code for package producing.
Some kernel functions call eth_rebuild_header(skb) to rebuild Mac header. However, in my case, it hangs my computer after being called. Google results answers that arp_find will crash the OS if the arp cache contains not entry for that IP address. But I'm sure the it exists in the arp cache as printed by shell command "arp -v".
static int build_and_xmit_tcp(char * eth, u_char * smac, u_char * dmac,
u_long sip, u_long dip,
u_short sport, u_short dport,
u_char * pkt, int pkt_len,
int syn, int ack, int fin,
__be32 seq, __be32 seq_ack)
{
struct sk_buff * skb = NULL;
struct net_device * dev = NULL;
struct ethhdr * ethdr = NULL;
struct iphdr * iph = NULL;
struct tcphdr * tcph = NULL;
u_char * pdata = NULL;
if(NULL == smac || NULL == dmac)
goto out;
if(NULL == (dev= dev_get_by_name(&init_net, eth)))
goto out;
skb = alloc_skb(pkt_len + sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
if(NULL == skb)
goto out;
skb_reserve(skb, LL_RESERVED_SPACE(dev));
skb->dev = dev;
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = __constant_htons(ETH_P_IP);
skb->ip_summed = CHECKSUM_NONE;
skb->priority = 0;
skb_set_network_header(skb, 0);
skb_put(skb, sizeof(struct iphdr));
skb_set_transport_header(skb, sizeof(struct iphdr));
skb_put(skb, sizeof(struct tcphdr));
pdata = skb_put(skb, pkt_len);
{
if(NULL != pkt)
memcpy(pdata, pkt, pkt_len);
}
tcph = tcp_hdr(skb);
memset(tcph, 0, sizeof(struct tcphdr));
tcph->source = sport;
tcph->dest = dport;
tcph->doff=5;
tcph->seq = htonl(seq);
tcph-> ack_seq= htonl( seq_ack);
tcph->psh = pkt_len>0? 1:0;
tcph ->fin = fin;
tcph->ack = ack;
tcph->syn=syn;
tcph->window=__constant_htons (65535);
skb->csum = 0;
tcph->check = 0;
iph = ip_hdr(skb);
iph->version = 4;
iph->ihl = sizeof(struct iphdr)>>2;
iph->frag_off = 0;
iph->protocol = IPPROTO_TCP;
iph->tos = 0;
iph->daddr = dip;
iph->saddr = sip;
iph->ttl = 0x40;
iph->tot_len = __constant_htons(skb->len);
iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph,iph->ihl);
skb->csum = skb_checksum(skb, iph->ihl*4, skb->len - iph->ihl * 4, 0);
tcph->check = csum_tcpudp_magic(sip, dip, skb->len - iph->ihl * 4, IPPROTO_TCP, skb->csum);
skb_push(skb, 14);
skb_set_mac_header(skb, 0);
ethdr = (struct ethhdr *)eth_hdr(skb);
// memcpy(ethdr->h_dest, dmac, ETH_ALEN);
// memcpy(ethdr->h_source, smac, ETH_ALEN);
ethdr->h_proto = __constant_htons(ETH_P_IP);
// arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
// dst_ha, dev->dev_addr, NULL);
eth_rebuild_header(skb); // kernel hang....
if(0 > dev_queue_xmit(skb)) {
dev_put (dev);
kfree_skb (skb);
}
return(NF_ACCEPT);
out:
dev_put (dev);
kfree_skb (skb);
return(NF_ACCEPT);
}
static int __init myhook_init(void)
{
printk("=========insert module......\n");
build_and_xmit_tcp(ETH_O, GWMAC_O, DMAC, in_aton(GWIP_O), in_aton(DIP), htons(8888), htons(DPORT),
"", 0,
1, 0, 0, 0, 0);
}
static void __exit myhook_fini(void)
{
printk("=========rmmod ......\n");
}
module_init(myhook_init);
module_exit(myhook_fini);
Google gives me some other solution. They say arp_ioctl can resolve the Mac address. However, the fact is that, arp_ioctl is compiled statically into vmlinuz, which is not exported as a symbol to other modules.
int arp_get(char *ifname, char *ipStr)
{
struct arpreq req;
struct sockaddr_in *sin;
int ret = 0;
int sock_fd = 0;
struct net_device * dev = NULL;
printk("arp ---- \n");
if(NULL == (dev= dev_get_by_name(&init_net, ifname))){
dev_put (dev);
printk("error dev get \n");
return -1;
}
struct net *net_arp = dev_net(dev);
memset(&req, 0, sizeof(struct arpreq));
sin = (struct sockaddr_in *)&req.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = in_aton(ipStr);
strncpy(req.arp_dev, ifname, 15);
ret = arp_ioctl(net_arp, SIOCGARP, &req); // can't be called
unsigned char *hw = (unsigned char *)req.arp_ha.sa_data;
printk("%#x-%#x-%#x-%#x-%#x-%#x\n", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]);
return 0;
}
Maybe I need make a socket structure, and try some upper functions based on a socket. But how to do it...
kernel version : 2.6.32
os version: ubuntu 9.10
gcc version : 4.41
int ip_xmit(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
struct tcphdr *tcph = tcp_hdr(skb);
printk("dst is %d\n", skb->_skb_dst);
int err;
// err = ip_route_input(skb, iph->daddr, iph->saddr, 0, skb->dev);
struct rtalbe *rt;
{
struct flowi fl = { .oif = 0,
.nl_u = { .ip4_u =
{ .daddr = iph->daddr,
.saddr = iph->saddr,
.tos = 0 } },
.proto = IPPROTO_TCP,
.flags = 0,
.uli_u = { .ports =
{ .sport = tcph->source,
.dport = tcph->dest } } };
if (err = ip_route_output_key(&init_net, &rt, &fl))
return err;
printk("err is %d\n", err);
}
skb_dst_set(skb, rt);
if(0 > ip_local_out(skb)) {
printk("dev error\n");
kfree_skb (skb);
return -1;
}
return 0;
}
function ip_route_output_key can obtain the route destination, and ip_local_out deliver the skb out.
I'm trying to make a LKM netfilter that drops incoming packets if the number of packets arrived exceeds a certain limit.
There are five ports that the packets comes through, and netfiltering is done for each of those ports.
Here's part of my LKM netfilter (it uses procfs to write from user program):
#define MAX_PORT 5
static unsigned short int port[MAX_PORT];
static unsigned long limit;
static char char_limit[256];
static unsigned long data_count[MAX_PORT];
bool check_port(unsigned short int);
static unsigned int my_hook_fn( void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *ip = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
unsigned int source, dest;
if(!skb) return NF_ACCEPT;
if(ip->protocol==IPPROTO_TCP)
{
source = htons((unsigned short int) th->source);
dest = htons((unsigned short int) th->dest);
printk(KERN_ALERT "source: %u, destination: %u\n", source, dest);
if(!check_port(source))
{
printk(KERN_ALERT "packet dropped!\n");
return NF_DROP;
}
}
return NF_ACCEPT;
}
bool check_port(unsigned short int source)
{
int i = 0;
bool found = false;
while(!found && i < MAX_PORT)
{
if(port[i] == source)
found = true;
else if(port[i] == 0)
{
port[i] = source;
found = true;
}
i++;
}
i--;
data_count[i]++;
if(data_count[i] >= limit)
{
data_count[i] = limit;
printk(KERN_ALERT "port %hu has reached the limit!\n", port[i]);
return false;
}
return true;
}
static struct nf_hook_ops my_nf_ops = {
.hook = my_hook_fn,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
};
In my hook function, the NF_DROP seems to be correctly returned.
However, the result in my user space program shows that it's not.
Next is my user space program; this produces results in txt files.
void *thread_recv(void *arg);
#define MAX_CON 5
#define BUF_SIZE 200
int port[MAX_CON];
char ip[20];
int sock[MAX_CON];
void error_handling(char *msg);
void main(){
int i;
unsigned long limit;
char char_limit[256];
FILE *fp;
printf("packet limit : ");
scanf("%lu", &limit);
sprintf(char_limit, "%lu", limit);
fp = fopen("/proc/myproc/myproc", "w");
if(fp == NULL)
printf("unable to open myproc\n");
else
fprintf(fp, "%s", char_limit);
fclose(fp);
struct sockaddr_in serv_adr;
pthread_t thread_id[MAX_CON];
printf("ip :\n");
scanf("%s",ip);
printf("<port> <port> <port> <port> <port>\n");
scanf("%d %d %d %d %d", &(port[0]), &(port[1]), &(port[2]), &(port[3]), &(port[4]));
printf("%s %d\n", ip, port[0]);
for(i=0;i<5;i++){
sock[i]=socket(PF_INET, SOCK_STREAM, 0);
if(sock[i]==-1)
error_handling("socket() error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(ip);
serv_adr.sin_port=htons(port[i]);
if(connect(sock[i], (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
error_handling("connect() error");
else
printf("port %d connected\n", port[i]);
pthread_create(&(thread_id[i]),NULL, thread_recv,(void*)&(sock[i]));
}
while(1); // do infinitely, so user should end by their own. Ctrl + C
}
void *thread_recv(void *arg){
int clnt_sock= *(int*)arg; // get socketnumber from main
int str_len=0, i; // recv byte length
int tport=0; // portnumber matching socketnumber
char msg[BUF_SIZE];
time_t timer;
struct tm *t;
struct timespec spec;
unsigned long ms;
FILE *fp;
char filename[20]={NULL};
for(i=0;i<5;i++)
if(sock[i]==clnt_sock)
tport=port[i];
sprintf(filename,"%d.txt",tport);
fp=fopen(filename,"w+");
printf("%d port thread run\n", tport);
while((str_len=read(clnt_sock, msg, sizeof(msg)))){
msg[str_len]=NULL;
timer= time(NULL);
t= localtime(&timer);
clock_gettime(CLOCK_REALTIME, &spec);
ms = round(spec.tv_nsec / 1.0e6);
fprintf(fp,"%d:%d:%d.%lu %d %s\n",t->tm_hour,t->tm_min,t->tm_sec,ms,str_len,msg);
}
fclose(fp);
}
void error_handling(char *msg){
fputs(msg, stderr);
fputc('\n', stderr);
exit(1);
}
Within the thread_recv function, a txt file is created with its name as the matching port number.
What I was expecting from this was that once packet is dropped, the resulting txt file will stop being updated.
For example, if the limit is 10, then only 10 socket information will be written to the file.
But even when the ports have reached the limit, they keep updating the resulting txt files.
Does that mean that the packets have not been dropped properly?
I attach here my kernel module I developed and the test I am using at application level
memalloc.c
/*
* DMA memory allocation
* This kernel module allocates coherent, non-cached memory
* and returns the physical and virtual address of the allocated buffer
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include "memalloc.h"
#define DEVICE_NAME "memalloc"
// Max number of buffers
#define BUFFER_MAX_NUMBER 16
// Structure for buffer information
struct bufferInfo {
int active;
int size;
dma_addr_t handle;
int virtualAddress;
int *kernelAddress;
};
static struct bufferInfo bufferInfoTable[BUFFER_MAX_NUMBER];
// Defines which buffer is currently active - for mmap
static int activeBufferID;
struct memAllocIF {
struct device *device_p;
dev_t dev_node;
struct cdev cdev;
struct class *class_p;
};
static struct memAllocIF interface;
// Methods
static int releaseBuffer(int i)
{
if (i > BUFFER_MAX_NUMBER)
{
printk("Wrong bufferID %d\n", i);
return -1;
}
printk("Releasing buffer %d\n", i);
bufferInfoTable[i].active = 0;
dma_free_coherent(NULL, bufferInfoTable[i].size, bufferInfoTable[i].kernelAddress, bufferInfoTable[i].handle);
return 0;
}
static int reserveBuffer(size_t size)
{
int i;
for (i = 0; i < BUFFER_MAX_NUMBER; i++)
{
if (bufferInfoTable[i].active == 0)
{
printk("Reserving buffer %d\n", i);
bufferInfoTable[i].active = 1;
break;
}
}
if (i < BUFFER_MAX_NUMBER)
{
bufferInfoTable[i].kernelAddress = dma_alloc_coherent(NULL, size, &bufferInfoTable[i].handle, GFP_KERNEL);
if (bufferInfoTable[i].kernelAddress == NULL)
{
printk("Allocation failure\n");
return -1;
}
bufferInfoTable[i].size = (int)size;
return i;
}
else
{
printk("No buffer available\n");
return -1;
}
}
static void cleanup(void)
{
int i;
for (i = 0; i < BUFFER_MAX_NUMBER; i++)
{
if (bufferInfoTable[i].active != 0)
{
dma_free_coherent(NULL, bufferInfoTable[i].size, bufferInfoTable[i].kernelAddress, bufferInfoTable[i].handle);
bufferInfoTable[i].active = 0;
}
}
}
static unsigned int memAllocGetVirtual (int i)
{
if (i > BUFFER_MAX_NUMBER)
{
printk("Wrong bufferID %d\n", i);
return -1;
}
if (bufferInfoTable[i].active == 0)
{
printk("Inactive buffer - ID %d\n", i);
return -1;
}
printk("request for buffer %d: vaddr = %X\n", i, (unsigned int)bufferInfoTable[i].virtualAddress);
return bufferInfoTable[i].virtualAddress;
}
static unsigned int memAllocGetPhysical (int i)
{
if (i > BUFFER_MAX_NUMBER)
{
printk("Wrong bufferID %d\n", i);
return -1;
}
return (unsigned int)bufferInfoTable[i].handle;
}
static long memAllocIoctl (struct file *fd, unsigned int cmd, unsigned long arg)
{
printk("received command %u arg %lu\n", cmd, arg);
switch(cmd)
{
case MEMALLOC_RESERVE:
return reserveBuffer(arg);
break;
case MEMALLOC_RELEASE:
return releaseBuffer(arg);
break;
case MEMALLOC_GET_VIRTUAL:
return memAllocGetVirtual(arg);
break;
case MEMALLOC_GET_PHYSICAL:
return memAllocGetPhysical(arg);
break;
case MEMALLOC_ACTIVATE_BUFFER:
if (arg > BUFFER_MAX_NUMBER || bufferInfoTable[arg].active == 0)
{
printk("Wrong bufferID %lu\n", arg);
return -1;
}
activeBufferID = arg;
return arg;
break;
default:
printk("Wrong command: %d\n", cmd);
return -1;
break;
}
}
static int memAllocMmap (struct file *fd, struct vm_area_struct *vma)
{
bufferInfoTable[activeBufferID].virtualAddress = dma_common_mmap(interface.device_p, vma, bufferInfoTable[activeBufferID].kernelAddress, bufferInfoTable[activeBufferID].handle, vma->vm_end-vma->vm_start);
printk("mmap for idx %d: vaddr = %X\n", activeBufferID, (int)bufferInfoTable[activeBufferID].virtualAddress);
return bufferInfoTable[activeBufferID].virtualAddress;
}
static int memAllocRelease(struct inode *in, struct file *fd)
{
cleanup();
return 0;
}
static int memAllocOpen(struct inode *ino, struct file *file)
{
file->private_data = container_of(ino->i_cdev, struct memAllocIF, cdev);
return 0;
}
static struct file_operations fops = {
.unlocked_ioctl = memAllocIoctl,
.mmap = memAllocMmap,
.release = memAllocRelease,
.open = memAllocOpen
};
static int __init memAllocInit(void)
{
int rc;
int i;
static struct class *local_class_p = NULL;
printk("Loading DMA allocation module\n");
// Allocate a character device from the kernel for this driver
rc = alloc_chrdev_region(&interface.dev_node, 0, 1, DEVICE_NAME);
if (rc)
{
printk("Unable to get a char device number\n");
return rc;
}
// Initialize the ter device data structure before registering the character device with the kernel
cdev_init(&interface.cdev, &fops);
rc = cdev_add(&interface.cdev, interface.dev_node, 1);
if (rc)
{
printk("Unable to add char device\n");
cdev_del(&interface.cdev);
return rc;
}
// Create the device in sysfs which will allow the device node in /dev to be created
local_class_p = class_create(THIS_MODULE, DEVICE_NAME);
interface.class_p = local_class_p;
// Create the device node in /dev so the device is accessible as a character device
interface.device_p = device_create(interface.class_p, NULL, interface.dev_node, NULL, DEVICE_NAME);
if (IS_ERR(interface.device_p))
{
printk("Unable to create the device\n");
class_destroy(interface.class_p);
cdev_del(&interface.cdev);
return rc;
}
for (i = 0; i < BUFFER_MAX_NUMBER; i++)
{
bufferInfoTable[activeBufferID].active = 0;
}
return 0;
}
static void __exit my_memAllocExit(void)
{
printk("Module unloading\n");
cleanup();
cdev_del(&interface.cdev);
device_destroy(interface.class_p, interface.dev_node);
class_destroy(interface.class_p);
unregister_chrdev_region(interface.dev_node, 1);
}
module_init(memAllocInit);
module_exit(my_memAllocExit);
MODULE_AUTHOR("me");
MODULE_DESCRIPTION("Create a buffer and return physical and virtual address, for DMA userspace driver");
MODULE_LICENSE("GPL");
memalloc.h
#ifndef MEMALLOC_H
#define MEMALLOC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <linux/types.h>
#include <asm/ioctl.h>
static long memAllocIoctl (struct file *, unsigned int, unsigned long);
static int memAllocMmap (struct file *, struct vm_area_struct *);
static int memAllocRelease (struct inode *, struct file *);
static int memAllocOpen(struct inode *, struct file *);
enum memAllocCmd
{
MEMALLOC_RESERVE = 0,
MEMALLOC_RELEASE = 1,
MEMALLOC_GET_VIRTUAL = 2,
MEMALLOC_GET_PHYSICAL = 3,
MEMALLOC_ACTIVATE_BUFFER = 4,
};
#ifdef __cplusplus
}
#endif
#endif /* MEMALLOC_H */
test.c
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
// derive this from memalloc.h
enum memAllocCmd
{
MEMALLOC_RESERVE = 0,
MEMALLOC_RELEASE = 1,
MEMALLOC_GET_VIRTUAL = 2,
MEMALLOC_GET_PHYSICAL = 3,
MEMALLOC_ACTIVATE_BUFFER = 4,
};
int main ()
{
int memAllocFd;
volatile int iVaddr;
volatile int oVaddr;
volatile int iVaddr_2;
volatile int oVaddr_2;
volatile void * iPaddr;
volatile void * oPaddr;
int iBufID;
int oBufID;
int size = 2048;
memAllocFd = open("/dev/memalloc", O_RDWR);
// create iBuffer
iBufID = ioctl(memAllocFd, MEMALLOC_RESERVE, size);
iPaddr = (void *)ioctl(memAllocFd, MEMALLOC_GET_PHYSICAL, iBufID);
ioctl(memAllocFd, MEMALLOC_ACTIVATE_BUFFER, iBufID);
iVaddr = (int)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, memAllocFd, 0);
ioctl(memAllocFd, MEMALLOC_GET_VIRTUAL, iBufID);
/*
if (iVaddr != iVaddr_2)
{
printf("Error: virtual addresses for buffer %d don't match: %X %X\n", iBufID, iVaddr, iVaddr_2);
}
*/
// create oBuffer
oBufID = ioctl(memAllocFd, MEMALLOC_RESERVE, size);
oPaddr = (void *)ioctl(memAllocFd, MEMALLOC_GET_PHYSICAL, oBufID);
ioctl(memAllocFd, MEMALLOC_ACTIVATE_BUFFER, oBufID);
oVaddr = (int)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, memAllocFd, 0);
ioctl(memAllocFd, MEMALLOC_GET_VIRTUAL, oBufID);
/*
if (oVaddr != oVaddr_2)
{
printf("Error: virtual addresses for buffer %d don't match: %X %X\n", oBufID, oVaddr, oVaddr_2);
}
*/
ioctl(memAllocFd, MEMALLOC_RELEASE, iBufID);
ioctl(memAllocFd, MEMALLOC_RELEASE, oBufID);
return 0;
}
Result of the test is
received command 0 arg 2048
Reserving buffer 0
received command 3 arg 0
received command 4 arg 0
mmap for idx 0: vaddr = 0
received command 0 arg 2048
Reserving buffer 1
received command 3 arg 1
received command 4 arg 1
mmap for idx 1: vaddr = 0
received command 1 arg 0
Releasing buffer 0
received command 1 arg 1
Releasing buffer 1
Which means that all ioctl calls with arg=MEMALLOC_GET_VIRTUAL are not executed, while all the others are.
What can be the reason for that?
Thanks,
Max
I am trying to use raw sockets to send packets from a transmitter to the receiver . The code works fine when i deploy both the transmitter and the receiver on my Mac or my friends Dell(Ubuntu 12.04 installed on both). I run the transmitter and receiver in two different terminal windows and it works fine.
But when i run the transmitter on one machine and the receiver on the other , the receiver does not receive any packets. Could someone point out the problem? I am very new to socket programming and therefore please forgive any stupid mistakes.
Transmitter :
/* Function to send a packet using sendto */
int SendPacket(int sockaddress,struct packet *mypacket, int packet_len)
{
int sent= 0;
if((sent = write(sockaddress, mypacket, packet_len)) != packet_len)
{ return 0; }
else
{ return 1; }
}
/* Function to create the raw socket for the monitor interface and also bind the socket to
the interface */
int create_raw_socket(char *dev)
{
struct sockaddr_ll sll;
struct ifreq ifr;
int fd, ifi, rb;
bzero(&sll, sizeof(sll));
bzero(&ifr, sizeof(ifr));
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
assert(fd != -1);
strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
assert(ifi != -1);
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_family = PF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_pkttype = PACKET_OTHERHOST;
rb = bind(fd, (struct sockaddr *)&sll,sizeof(sll));
assert(rb != -1);
return fd;
}
/* Main function */
int main(int argc, char**argv)
{
int x,fd,s;
int sockaddress,len;
char dest_packet[PACKET_LENGTH];
int count= atoi(argv[2]);
char ch;
struct packet mypacket;
struct ieee80211_radiotap_header ratap_header;
struct ieee80211_hdr_3addr iee802_header;
unsigned char addr1[ETH_ALEN] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
unsigned char addr2[ETH_ALEN] = {0x13,0x22,0x33,0x44,0x55,0x66};
unsigned char addr3[ETH_ALEN] = {0x13,0x22,0x33,0x44,0x55,0x66};
/* Radio tap header data */
ratap_header.it_version = 0x00;
ratap_header.it_pad = 0x00;
ratap_header.it_len = 0x06;
ratap_header.it_pad2 = 0x00;
ratap_header.it_present = 0x8000;
mypacket.rtap_header = ratap_header;
/* ieee80211 header data */
iee802_header.frame_ctl = 0x0801;
iee802_header.duration_id = 0x0000;
strcpy(iee802_header.addr1,addr1);
strcpy(iee802_header.addr2,addr2);
strcpy(iee802_header.addr3,addr3);
iee802_header.seq_ctl = 0x1086;
mypacket.iee802_header=iee802_header;
/* Payload */
unsigned char payload[PACKET_LENGTH]="test";
unsigned char stop_injection[5]="stop";
strcpy(mypacket.payload , payload);
len = sizeof(mypacket) ;
/* Sending the packet over the interface */
printf("\n Press Y to start packet injection \n");
while((ch = getchar()) != 'Y');
while((count--) > 0)
{
sockaddress = create_raw_socket(argv[1]);
if(!SendPacket(sockaddress, &mypacket, len))
perror("Error sending packet");
else
{
printf("Packet sent successfully with payload : %s\n" , mypacket.payload);
printf("\n size of the packet being send is %d \n " , len);
}
}
/* Packet to indicate the end of reception */
strcpy(mypacket.payload , stop_injection);
len = sizeof(mypacket) ;
int temp=SendPacket(sockaddress , &mypacket , len);
close(sockaddress);
printf("\n End of packet transmission ........................ \n");
return 0;
}
Receiver :
int main(int argc, char **argv)
{
struct sockaddr addr;
int sock_fd, fromlen,s;
char buf[PACKET_LENGTH];
char *dev = argv[1];
struct packet mypacket;
struct packet *ptr;
int recv_count=0;
sock_fd = create_raw_socket(dev); /* Creating the raw socket */
printf("\n Waiting to receive packets ........ \n");
while(1)
{
fromlen=sizeof(addr);
int x= recvfrom(sock_fd,&mypacket,sizeof(struct packet),0,&addr,&fromlen);
struct sockaddr_ll* temp;
temp = (struct sockaddr_ll*)(&addr);
if(temp->sll_pkttype == 4)
{
recv_count++;
if(strcmp(mypacket.payload , "stop") == 0)
break;
/* Payload received */
printf("\nPayload Received from client : %s \n ", mypacket.payload);
}
}
close(sock_fd);
return 0;
Data structures :
struct ieee80211_radiotap_header {
unsigned char it_version;
unsigned char it_pad;
uint16_t it_len;
uint16_t it_pad2;
uint32_t it_present;
};
/* Structure for 80211 header */
struct ieee80211_hdr_3addr {
uint16_t frame_ctl;
uint16_t duration_id;
unsigned char addr1[ETH_ALEN];
unsigned char addr2[ETH_ALEN];
unsigned char addr3[ETH_ALEN];
uint16_t seq_ctl;
} __attribute__ ((packed));
/* Structure of the packet containing the radiotap header, ieee802.11 header and payload
*/
struct packet {
struct ieee80211_radiotap_header rtap_header;
struct ieee80211_hdr_3addr iee802_header;
unsigned char payload[30];
};
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <linux/if.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#define NIC_NAME "wlan0"
/*our MAC address*/
static uint8_t gu8a_src_mac[6] = {0x11, 0x22, 0x33, 0x44 0x55, 0x66};
/*other host MAC address*/
static uint8_t gu8a_dest_mac[6] = {0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC};
int32_t get_nic_index (uint8_t *pu8_nic_card_name);
void* sock_recv_thread (void *p_arg);
int
main (void)
{
struct sockaddr_ll s_dest_addr;
int32_t s32_sock = -1;
int32_t s32_res = -1;
pthread_t ul_recv_thd_id = -1;
uint16_t u16_data_off = 0;
uint16_t u16_i = 0;
uint8_t *pu8a_frame = NULL;
uint8_t *pu8a_data = NULL;
printf ("Socket raw test\n");
(void) memset (&s_dest_addr, 0, sizeof (s_dest_addr));
pu8a_frame = (uint8_t *) calloc (ETH_FRAME_LEN, 1);
if( NULL == pu8a_frame )
{
printf ("Could not get memory for the transmit frame\n");
goto LABEL_CLEAN_EXIT;
}
u16_data_off = (uint16_t) (ETH_FRAME_LEN - ETH_DATA_LEN);
pu8a_data = pu8a_frame + u16_data_off;
s32_sock = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
if( -1 == s32_sock )
{
perror ("Could not create the socket");
goto LABEL_CLEAN_EXIT;
}
printf ("Socket created\n");
fflush (stdout);
(void) pthread_create (&ul_recv_thd_id, NULL, sock_recv_thread, &s32_sock);
sleep (1);
s_dest_addr.sll_family = AF_PACKET;
/*we don't use a protocol above ethernet layer, just use anything here*/
s_dest_addr.sll_protocol = htons(ETH_P_ALL);
s_dest_addr.sll_ifindex = get_nic_index ((uint8_t *) NIC_NAME);
s_dest_addr.sll_hatype = ARPHRD_ETHER;
s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING
s_dest_addr.sll_halen = ETH_ALEN;
/*MAC - begin*/
s_dest_addr.sll_addr[0] = gu8a_dest_mac[0];
s_dest_addr.sll_addr[1] = gu8a_dest_mac[1];
s_dest_addr.sll_addr[2] = gu8a_dest_mac[2];
s_dest_addr.sll_addr[3] = gu8a_dest_mac[3];
s_dest_addr.sll_addr[4] = gu8a_dest_mac[4];
s_dest_addr.sll_addr[5] = gu8a_dest_mac[5];
/*MAC - end*/
s_dest_addr.sll_addr[6] = 0x00;/*not used*/
s_dest_addr.sll_addr[7] = 0x00;/*not used*/
/*set the frame header*/
(void) memcpy (pu8a_frame, gu8a_dest_mac, ETH_ALEN);
(void) memcpy (pu8a_frame+ETH_ALEN , gu8a_src_mac, ETH_ALEN);
printf ("******Sending data using raw socket over '" NIC_NAME "'\n");
while( 1 )
{
(void) memset (&pu8a_data[u16_data_off], '\0', ETH_DATA_LEN);
(void) snprintf ((char *) &pu8a_data[u16_data_off],
ETH_DATA_LEN,
"Raw packet test, %d",
u16_i++);
s32_res = sendto (s32_sock,
pu8a_frame,
ETH_FRAME_LEN,
0,
(struct sockaddr*)&s_dest_addr,
sizeof(s_dest_addr));
if( -1 == s32_res )
{
perror ("Socket send failed");
goto LABEL_CLEAN_EXIT;
}
sleep (1);
}
/*printf ("Waiting for receive thread to exit\n");
pthread_join (ul_recv_thd_id, NULL);*/
LABEL_CLEAN_EXIT:
if( s32_sock > 0 )
{
close (s32_sock);
}
printf ("***** Raw Socket test- end\n");
return EXIT_SUCCESS;
}
void*
sock_recv_thread (void *p_arg)
{
struct sockaddr_ll s_src_addr;
int32_t s32_sock = * ((int32_t *)p_arg);
int32_t s32_res = -1;
uint16_t u16_data_off = 0;
uint8_t *pu8a_frame = NULL;
printf ("Socket receive thread\n");
u16_data_off = (uint16_t) (ETH_FRAME_LEN - ETH_DATA_LEN);
pu8a_frame = (uint8_t*) calloc (ETH_FRAME_LEN, 1);
if( NULL == pu8a_frame )
{
printf ("Could not get memory for the receive frame\n");
goto LABEL_CLEAN_EXIT;
}
(void) memset (&s_src_addr, 0, sizeof (s_src_addr));
s_src_addr.sll_family = AF_PACKET;
/*we don't use a protocol above ethernet layer, just use anything here*/
s_src_addr.sll_protocol = htons(ETH_P_ALL);
s_src_addr.sll_ifindex = get_nic_index ((uint8_t *) NIC_NAME);
s_src_addr.sll_hatype = ARPHRD_ETHER;
s_src_addr.sll_pkttype = PACKET_HOST;//PACKET_OTHERHOST;
s_src_addr.sll_halen = ETH_ALEN;
s32_res = bind (s32_sock,
(struct sockaddr *) &s_src_addr,
sizeof(s_src_addr));
if( -1 == s32_res )
{
perror ("Could not bind to the socket");
goto LABEL_CLEAN_EXIT;
}
printf ("Socket bind successful\n");
while( 1 )
{
struct sockaddr_ll s_sender_addr;
socklen_t u32_sender_addr_len = sizeof (s_sender_addr);
(void) memset (&s_sender_addr, 0, sizeof (s_sender_addr));
s32_res = recvfrom (s32_sock,
pu8a_frame,
ETH_FRAME_LEN,
0,
(struct sockaddr *) &s_sender_addr,
&u32_sender_addr_len);
if( -1 == s32_res )
{
perror ("Socket receive failed");
break;
}
else if( s32_res < 0 )
{
perror ("Socket receive, error ");
}
else
{
uint16_t u16_i = 0;
printf ("Received data from ");
for( u16_i=0; u16_i<sizeof(s_sender_addr.sll_addr)-2; u16_i++ )
{
printf ("%02x:", s_sender_addr.sll_addr[u16_i]);
}
printf ("\t");
printf ("Received data %s\n\n", &pu8a_frame[u16_data_off]);
}
}
LABEL_CLEAN_EXIT:
return (NULL);
}
int32_t
get_nic_index (uint8_t *pu8_nic_card_name)
{
int32_t s32_sock_fd = -1;
int32_t s32_res = -1;
struct ifreq s_ifr;
(void) memset (&s_ifr, 0, sizeof (s_ifr));
s32_sock_fd = socket (AF_INET, SOCK_DGRAM, 0);
if( -1 == s32_sock_fd )
{
perror ("get_nic_index(): socket failed");
goto LABEL_CLEAN_EXIT;
}
s_ifr.ifr_addr.sa_family = AF_INET;
strncpy(s_ifr.ifr_name, (char *) pu8_nic_card_name, IFNAMSIZ);
s32_res = ioctl(s32_sock_fd, SIOCGIFINDEX, &s_ifr);
if( -1 == s32_res )
{
perror ("get_nic_index(): ioctl failed");
}
close (s32_sock_fd);
LABEL_CLEAN_EXIT:
return (s_ifr.ifr_ifru.ifru_ivalue);
}
My code was working absolutely fine before the launch of iPhone SDK 3.0 , I am using socket functions to send data and receive data. What changes must i make to make it compatible for 3.0+.
-(int)InitSocket:(int)nPort: (NSString*)sServer{
if(sServer == nil)
{
return -1;
}
m_nPort = nPort;
sServerAddress = sServer;
const char* pServer = nil;
pServer = [sServer cStringUsingEncoding:NSASCIIStringEncoding];
m_nSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in servAddr;
memset(&servAddr, 0 , sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(pServer);
servAddr.sin_port = htons(m_nPort);
pfd.fd = m_nSock;
pfd.events = POLLIN | POLLERR| POLLHUP | POLLNVAL;
pfd.revents = 0;
m_nTimeout = -1;
int f = fcntl(m_nSock, F_GETFL, 0);
fcntl(m_nSock, F_SETFL, f | O_NONBLOCK |O_NDELAY);
int opt = 1;
setsockopt(m_nSock, SOL_SOCKET, SO_KEEPALIVE, (const void*)&opt,(socklen_t)sizeof(opt));
struct timeval timeout;
fd_set wset;
FD_ZERO(&wset);
FD_SET(m_nSock, &wset);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
return 0;
}
This Code for sending data
-(int)SendData:(size_t) nSize: (NSString*) buffer{
int nTotalSent = 0;
const char *pSend = [buffer cStringUsingEncoding:NSASCIIStringEncoding];
while(nTotalSent != nSize)
{
int nSent = send(m_nSock, (const void*)pSend+nTotalSent, nSize-nTotalSent, 0);
if(nSent == -1)
{
return nSent;
}
nTotalSent += nSent;
}
return nTotalSent;
}
Will the above code works in iPhone SDK 3.0+ , what changes i need to employ to make it work.
Thanks
You could start by properly checking for errors. All those functions that you use return an error code if something goes wrong and you will never know.