libpcap fails to capture packets after upgrading to new linux ethernet driver - networking

I have an old system running a custom 2.6.15 kernel that uses libpcap (version 1.1.1). Recently I've changed my network card with Intel 82575EB chipset that requires me to update the driver to igb.ko (was e1000.ko). After the update, libpcap stop capturing packets. I modified a sample test code from tcpdump website that captures 1 packet and print the header information, libpcap return header.len of 1358 and header.caplen of 42, whereas in e1000 case, both packet.len and packet.caplen returns 1358. I've tried disabling MSI/MSI-X and increase the MTU but nothing works. Is there any other options I need to set to get the igb driver to work with libpcap?
Here's the sample test program (courtesy of tcpdump/libpcap team):
#include <pcap.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
pcap_t *handle; /* Session handle */
char dev[20]; /* The device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
struct bpf_program fp; /* The compiled filter */
bpf_u_int32 mask; /* Our netmask */
bpf_u_int32 net; /* Our IP */
struct pcap_pkthdr header; /* The header that pcap gives us */
const u_char *packet; /* The actual packet */
if (argc <= 1) return(1);
strcpy(dev, argv[1]);
/* Find the properties for the device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
net = 0;
mask = 0;
}
/* Open the session in promiscuous mode */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
return(2);
}
/* Grab a packet */
packet = pcap_next(handle, &header);
/* Print its length */
printf("packet length [%d]; captured length [%d]\n", header.len, header.caplen);
/* And close the session */
pcap_close(handle);
return(0);
}

Try libpcap 1.4.0, which is currently the most recent release; there's a bug in 1.1.1 that, as I remember, could cause a packet to be supplied with a too-short caplen even though you've supplied a sufficiently-large snapshot length argument to pcap_open_live() (which you have - BUFSIZ is typically somewhere between 1K and 4K, both of which are bigger than 42, and I think it's 4K on Linux).

Related

printf alternative when using "define _GNU_SOURCE"

After reading https://www.quora.com/How-can-I-bypass-the-OS-buffering-during-I-O-in-Linux I want to try to access data on the serial port with the O_DIRECT option, but the only way I can seem to do that is by adding the GNU_SOURCE define but when I tried to execute the program, nothing at all is printed on the screen.
If I remove "#define _GNU_SOURCE" and compile, then the system gives me an error on O_DIRECT.
If I remove the define and the O_DIRECT flag, then incorrect (possibly outdated) data is always read, but the data is printed on the screen.
I still want to use the O_DIRECT flag and be able to see the data, so I feel I need an alternative command to printf and friends, but I don't know how to continue.
I attached the code below:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>
#define TIMEOUT 5
int main(){
char inb[3]; //our byte buffer
int nread=0; //number bytes read from port
int n; //counter
int iosz=128; //Lets get 128 bytes
int fd=open("/dev/ttyS0", O_NOCTTY | O_RDONLY | O_SYNC | O_DIRECT); //Open port
tcflush(fd,TCIOFLUSH);
for(n=0;n<iosz;n++){
int s=time(NULL); //Start timer for 5 seconds
while (time(NULL)-s < TIMEOUT && nread < 1){
inb[0]='A'; //Fill buffer with bad data
inb[1]='B';
inb[2]='C';
nread=read(fd,(char*)inb,1); //Read ONE byte
tcflush(fd,TCIOFLUSH);
if (nread < 0 || time(NULL)-s >= TIMEOUT){
close(fd); //Exit if read error or timeout
return -1;
}
}
printf("%x:%d ",inb[0] & 0xFF,nread); //Print byte as we receive it
}
close(fd); //program ends so close and exit
printf("\n"); //Print byte as we receive it
return 0;
}
First off, I'm no expert on this topic, just curious about it, so take this answer with a pinch of salt.
I don't know if what you're trying to do here (if I'm not looking at it the wrong way it seems to be to bypass the kernel and read directly from the port to userspace) was ever a possibility (you can find some examples, like this one but I could not find anything properly documented) but with recent kernels you should be getting an error running your code, but you're not catching it.
If you add these lines after declaring your port:
...
int fd=open("/dev/ttyS0", O_NOCTTY | O_RDONLY | O_SYNC | O_DIRECT );
if (fd == -1) {
fprintf(stderr, "Error %d opening SERIALPORT : %s\n", errno, strerror(errno));
return 1;
}
tcflush(fd,TCIOFLUSH);
....
When you try to run you'll get: Error 22 opening SERIALPORT : Invalid argument
In my humble and limited understanding, you should be able to get the same effect changing the settings on termios to raw, something like this should do:
struct termios t;
tcgetattr(fd, &t); /* get current port state */
cfmakeraw(&t); /* set port state to raw */
tcsetattr(fd, TCSAFLUSH, &t); /* set updated port state */
There are many good sources for termios, but the only place I could find taht also refers to O_DIRECT (for files) is this one.

Use libcryptsetup to open a plain encrypted partition

I have a deployed kiosk system which mounts an encrypted partition at boot time using crytpsetup and a key file on disk as such:
cryptsetup open --type plain --key-file /root/key.bin /dev/sda3 sda3
This yields a /dev/mapper/sda3 device which I can then mount for data access.
I am moving the key to a smart card and want to open the partition using libcryptsetup so the key is not exposed on the command line. Unfortunately, the only example given in the cryptsetup source is for LUKS.
I have tried to reverse engineer the cryptsetup source to get the correct library calls but have been frustrated by the complexity of the options.
Are there examples of other projects which use the library for plain encryption or perhaps a skeleton of the library calls required to duplicate the actions of the command line invocation?
The basic sequence of the library calls required for duplicating the actions on command line to open an encrypted partition using cryptsetup library will be as follows
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>
#include <libcryptsetup.h>
int activate_and_check_status(const char *path, const char *device_name)
{
struct crypt_device *cd;
struct crypt_active_device cad;
int r;
/*
* LUKS device activation example.
* It's sequence of sub-steps: device initialization, LUKS header load
* and the device activation itself.
*/
r = crypt_init(&cd, path);
if (r < 0 ) {
printf("crypt_init() failed for %s.\n", path);
return r;
}
/*
* crypt_load() is used to load the LUKS header from block device
* into crypt_device context.
*/
r = crypt_load(cd, /* crypt context */
CRYPT_LUKS1, /* requested type */
NULL); /* additional parameters (not used) */
if (r < 0) {
printf("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
crypt_free(cd);
return r;
}
/*
* Device activation creates device-mapper devie mapping with name device_name.
*/
r = crypt_activate_by_passphrase(cd, /* crypt context */
device_name, /* device name to activate */
CRYPT_ANY_SLOT,/* which slot use (ANY - try all) */
"foo", 3, /* passphrase */
CRYPT_ACTIVATE_READONLY); /* flags */
if (r < 0) {
printf("Device %s activation failed.\n", device_name);
crypt_free(cd);
return r;
}
printf("LUKS device %s/%s is active.\n", crypt_get_dir(), device_name);
printf("\tcipher used: %s\n", crypt_get_cipher(cd));
printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));
/*
* Get info about active device (query DM backend)
*/
r = crypt_get_active_device(cd, device_name, &cad);
if (r < 0) {
printf("Get info about active device %s failed.\n", device_name);
crypt_deactivate(cd, device_name);
crypt_free(cd);
return r;
}
printf("Active device parameters for %s:\n"
"\tDevice offset (in sectors): %" PRIu64 "\n"
"\tIV offset (in sectors) : %" PRIu64 "\n"
"\tdevice size (in sectors) : %" PRIu64 "\n"
"\tread-only flag : %s\n",
device_name, cad.offset, cad.iv_offset, cad.size,
cad.flags & CRYPT_ACTIVATE_READONLY ? "1" : "0");
crypt_free(cd);
return 0;
}
The API references for luks format, open, activate and deactivate with examples for cryptsetup is available at this link:
cryptsetup API

rs-485 USB to RS485 C code

#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <sys/ioctl.h> /* ioctl() */
void main(void)
{
int fd;/*File Descriptor*/
printf("\n +----------------------------------+");
printf("\n | USB To RS485 Write |");
printf("\n +----------------------------------+");
/*------------------------------- Opening the Serial Port -------------------------------*/
/* Change /dev/ttyUSB0 to the one corresponding to your system */
fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter */
/* O_RDWR Read/Write access to serial port */
/* O_NOCTTY - No terminal will control the process */
if(fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyUSB0 ");
else
printf("\n ttyUSB0 Opened Successfully ");
/*---------- Setting the Attributes of the serial port using termios structure --------- */
struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
cfsetispeed(&SerialPortSettings,B4800); /* Set Read Speed as 9600 */
cfsetospeed(&SerialPortSettings,B4800); /* Set Write Speed as 9600 */
SerialPortSettings.c_cflag &= PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS7; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 1; /* Read at least 10 character */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none");
/*---------------------------------------- Controlling RTS and DTR Pins --------------------------------------*/
/* ~RTS(USB2SERIAL) ---> ~RE(MAX485) */
/* ~DTR(USB2SERIAL) ---> DE(MAX485) */
/*------------------------- Putting MAX485 chip in USB2SERIAL in Transmit Mode ---------------------------*/
// //
// ----+ +-----------+ H +-----------+ //
// | | ~RTS| --------------> |~RE | //
// PC |==========>| FT232 | | MAX485 +(A,B)~~~~~~~~~~~~~~~>Data out(RS485) //
// | USB | ~DTR| --------------> | DE | Twisted Pair //
// ----+ +-----------+ H +-----------+ //
// //
//--------------------------------------------------------------------------------------------------------//
//TxMode - DE->High,~RE -> High
int RTS_flag,DTR_flag;
RTS_flag = TIOCM_RTS; /* Modem Constant for RTS pin */
DTR_flag = TIOCM_DTR; /* Modem Constant for DTR pin */
ioctl(fd,TIOCMBIC,&RTS_flag);/* ~RTS = 1,So ~RE pin of MAX485 is HIGH */
ioctl(fd,TIOCMBIC,&DTR_flag);/* ~DTR = 1,So DE pin of MAX485 is HIGH,Transmit Mode enabled */
/*------------------------------- Write data to serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char write_buffer[] = "///?01!"; /* Buffer containing characters to write into port */
char write_buffer1[] = {'\r','\n'};
int bytes_written = 0; /* Value for storing the number of bytes written to the port */
bytes_written = write(fd,write_buffer,7);/* use write() to send data to port */
/* "fd" - file descriptor pointing to the opened serial port */
/* "write_buffer" - address of the buffer containing data */
/* "sizeof(write_buffer)" - No of bytes to write */
printf("\n %s written to ttyUSB0",write_buffer);
bytes_written = write(fd,write_buffer1,2);/* use write() to send data to port */
/* "fd" - file descriptor pointing to the opened serial port */
/* "write_buffer" - address of the buffer containing data */
/* "sizeof(write_buffer)" - No of bytes to write */
printf("\n %s written to ttyUSB0",write_buffer);
printf("\n %d Bytes written to ttyUSB0", bytes_written);
printf("\n +----------------------------------+\n\n");
char buf[20000];
sleep(2);
while(1)
{
printf("tring to read port\n");
int res = read(fd,buf,1);
sleep(1);
printf("%c :: %d\n",buf[0],res);
}
printf("\n +----------------------------------+\n\n\n");
close(fd); /* Close the serial port */
}
--------------------------------------------------------
Setting for running the code :BAUD RATE is 4800 Databits is 7 , Parity is EVEN, and Stopbit is 1.
If i compile the code and run it is not working. Before running the code if i open and close the minicom with BAUD B4800 & 7E1 then my code is working.
Can any one suggest where is the problem why it is not working.

iptables netfilter copying the packet

I was wondering if there is a way to copy a packet using iptables/netfilter, change it and deliver both to the application.
Basically, I want to capture a packet from a flow and redirect it to some queue, then I want to copy it, issue the verdict for it(I know how to do this part in C),then I need to change something in the copied version, AND issue the verdict for that "modified" packet too.
Basically I want the app to receive both the unmodified and the modified version.
Is this possible?
Thanks in advance for any help.
Your mission can be achieved with libipq library. The tutorial in following like focus on copying & modifying a packet in userspace.
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.205.2605&rep=rep1&type=pdf
You need to know C to work on it. Alternatively "Scapy" - a python based packet maipulation tool can be used.
#include <linux/netfilter.h>
#include <libipq.h>
/*
* Used to open packet ; Insert a iptables rule to get packet here
* iptables -I 1 [INPUT|OUTPUT|FORWARD] <packet header match> -j QUEUE
*/
#include <linux/netfilter.h>
#include <libipq.h>
#include <stdio.h>
#define BUFSIZE 2048
static void die(struct ipq_handle *h)
{
ipq_destroy_handle(h);
exit(1);
}
int main(int argc, char **argv)
{
int status;
unsigned char buf[BUFSIZE];
struct ipq_handle *h;
h = ipq_create_handle(0, NFPROTO_IPV4);
if (!h)
die(h);
status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
if (status < 0)
die(h);
do{
status = ipq_read(h, buf, BUFSIZE, 0);
if (status < 0)
die(h);
if (ipq_message_type(buf) == IPQM_PACKET){
ipq_packet_msg_t *m = ipq_get_packet(buf);
status = ipq_set_verdict(h, m->packet_id, NF_ACCEPT, 0, NULL);
}
} while (1);
ipq_destroy_handle(h);
return 0;
}

send a log message to remote syslogd server in my own c code

all experts,
I'm writing my own daemon that has similar function as the standard syslogd. Below is my c code to send a log message to remote syslogd server 10.0.0.3. The remote syslogd server 10.0.0.3 is a windows machine and I run Kiwi Syslog Service Manager there (downloaded from Internet). The Kiwi syslog server can receive log messages I sent, but the messages it shows are either empty or has only one character (the last column is the message):
10-11-2011 14:21:01 User.Emerg 10.0.0.1 O
10-11-2011 14:21:00 User.Emerg 10.0.0.1 T
10-11-2011 14:21:01 User.Warning 10.0.0.1
I don't know which excactly corresponds to my pLogMessage in the code, but it got to be one of these 3.
Can any expert tell me why the received message is not corret? Thanks a lot!
char *pLogMessage = "Tue Oct 11 11:14:20 2011:cli:journal:LOG_INFO: cgr_cli_main.c:232--his books are all jammed in the close\r\n";
CGR_INT socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sockServerAddr;
memset(&sockServerAddr, 0, sizeof(struct sockaddr_in));
sockServerAddr.sin_family = AF_INET;
sockServerAddr.sin_addr.s_addr = inet_addr("10.0.0.3"); /* remote syslogd server ip */
sockServerAddr.sin_port = htons(514);
/* send the log message to the socket */
size_t bytesSent = sendto(socketFileDescriptor, /* socket file descriptor */
pLogMessage, /* message to be sent */
sizeof(pLogMessage), /* message size in bytes */
0, /* flag: ? */
(struct sockaddr *)&sockServerAddr, /* points to a sockaddr structure containing the destination address */
sizeof(sockServerAddr)); /* specifies the length of the sockaddr structure pointed to by the previous argument */
/* close socket */
close(socketFileDescriptor);
A proper syslog message has the following format:
<30>Oct 12 12:49:06 host app[12345]: syslog msg
The number within the <> signs is the priority which is composed of the severity and facility values. Also you are missing the hostname from the message. This may be a reason why the syslog server fails to parse your message. The line terminator \r\n is not required for UDP. See rfc3164 for the details.
The code is also buggy, you should use strlen(pLogMessage) instead of sizeof(pLogMessage).

Resources