simple examples of how to

Saturday, October 17, 2009

Linux Networking Kernel Function Map V-0.1


Hope it helps to understand linux networking kernel

Friday, October 16, 2009

bypassing socket buffer using raw socket... interesting

setsockopt HDRINCL 'error code 22, Invalid arg' OpenBSD 3.3 using gcc 2.95.3

Asked by crizza in OpenBSD

Tags: hdrincl, setsockopt

Hi all. Im having problems allowing the kernel to let me include my own ip header.

I am writing a network/firewall and protocol analysis tool for my work.

Running on x86/OpenBSD 3.3 platform using gcc 2.95.3 with no special opts apart from debugging.

The src compiles ok, but when run; 'perror' recieves error code '22' 'invalid arg' from setsockopt ( i presume ) and I cannot understand why???

I have tested the prog bypassing the setsockopt function and it works ok, alas with the kernel ip header included ;(

Please forgive me if its a glaringly obvious error on my part as I am returning to c & *nix after a few years in the wilderness.

N.B Apologies, but my code seems to have lost all its tabs when i posted it



Many thanks for any help offered

Chris

--------------------------------------------------

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "decs.h"

int main( void )
{
unsigned int tport;
unsigned short uno, s;
struct iphead *iphead;
struct tcphead *tcphead;
struct sockaddr_in dst;
char dgram[BUFFER];
tport = 1500;
uno = 1;

if( getuid() ) {
printf("ALERT: You need to be r00t\n");
exit( 0 );
}

if ( !( s = socket( AF_INET, SOCK_RAW, IPPROTO_TCP ) ) )
perror("socket error");

// cast dgram to struct and point *iphead at element
iphead = ( struct iphead *) dgram;
// as above but with size of ip_header offset
tcphead = ( struct tcphead *) dgram + sizeof( struct iphead );

dst.sin_family = AF_INET;
dst.sin_port = htons( tport );
dst.sin_addr.s_addr = inet_addr( "192.168.0.7" );
memset( dgram, 0, BUFFER );

// custom values
iphead->ip_hl = 5;
iphead->ip_v = 4;
iphead->ip_tos = 0;
iphead->ip_len = BUFFER;
iphead->ip_id = htonl( 1234 );
iphead->ip_off = 0;
iphead->ip_ttl = 255;
iphead->ip_p = 6; // tcp
iphead->ip_sum = 0; // set to 0 by default
iphead->ip_src.s_addr = inet_addr( "192.168.0.1" );
iphead->ip_dst.s_addr = dst.sin_addr.s_addr;
tcphead->th_sport = htons( 1234 );
tcphead->th_dport = htons( tport );
tcphead->th_seq = random();
tcphead->th_ack = 0;
tcphead->th_x2 = 0;
tcphead->th_off = 0;
tcphead->th_flags = TH_SYN; // init new connection
tcphead->th_win = htonl( MAX_WINDOW );
tcphead->th_sum = 0;
tcphead->th_urp = 0; // no urgency flags

// generate chksum
iphead->ip_sum = chksum( ( unsigned short *)dgram, iphead->ip_len >> 1 );

// header check
if ( setsockopt( s,
IPPROTO_IP,
IP_HDRINCL,
&uno,
sizeof( uno ) ) < style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> perror( "Alert: setsockopt cannot set HDRINCL" );
exit( 1 );
}

// kill with control-c
while( 1 ) {
if( sendto( s,
dgram,
sizeof( dgram ),
0,
( struct sockaddr * ) &dst,
sizeof( dst ) ) < style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> perror( "Alert: sendto failed" );
exit( 1 );
} else {
printf( "." );
}
}
exit( 0 );
}


--------------------------------------------------

// Decs.h

#ifndef H_DECS
#define H_DECS
#define BUFFER sizeof( struct iphead ) + sizeof( struct tcphead )
#define MAX_WINDOW 65535

__BEGIN_DECLS
unsigned short chksum( unsigned short *, int );
void chkhdr( unsigned short );
__END_DECLS

/* initial command line opts */
typedef struct opts {
unsigned char *cfg; // absolute path
unsigned char *host; // dest host
unsigned short int port; // dest port
unsigned short int pkts; // number of packets to send
}cli_opts;

struct iphead {
unsigned char ip_hl, ip_v; // 4 bits respectively
unsigned char ip_tos; // limo or taxi???
unsigned short int ip_len; // total len of header and data
unsigned short int ip_id; // help assemble fragments
unsigned short ip_off; // 3bit control flags, 13bit offset. Do i frag?
unsigned char ip_ttl; // --ttl each hop. if 0 then destroy
unsigned char ip_p; // next level protocol
unsigned short int ip_sum; // header checksum
struct in_addr ip_src, ip_dst; // source and dest
};

struct tcphead {
unsigned short int th_sport; // source port
unsigned short int th_dport; // destination port
unsigned int th_seq; // seq number of first data octet in segment
unsigned int th_ack; // next seq num expected to recieve
unsigned char th_x2, th_off; /* x2 reserved for future use ( must be 0 )
* data_off indicates where data begins */
unsigned char th_flags; /* TH_URG: urgent, TH_ACK: yup, TH_PSH, do not
* buffer segment push straight thro stack
* TH_RST: tell peer to terminate
* TH_SYN: init new connect
* TH_FIN: close connection
* control bits */
unsigned short int th_win; /* amount of data octets to be accepted
* including original seq_num octet */
unsigned short int th_sum; // initial value = 0
unsigned short int th_urp; // only used if TH_URG is set in tcp_flags
};


/* standard BSD checksum */
unsigned short chksum ( unsigned short *addr, int len ) {
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;

/* 32 bit accumulator 'sum', add sequential 16 bit words to it '*w'.
* At the end fold back all the carry bits from top 16 bits into
* lower 16 bits */
while ( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}


// mop up odd byte, if necessary
if ( nleft == 1 ) {
*( u_char * ) ( &answer ) = *( u_char * )w ;
sum += answer;
}

// add back carry outs from top 16 bits to lower 16 bits
sum = ( sum >> 16 ) + ( sum + 0xffff ); // add hi 16 to low 16
sum += ( sum >> 16 ); // add carry
answer = ~sum; // truncate to 16bits
return ( answer );
}

// check kernel hasnt inserted header
void chkhdr( unsigned short sockd ) {

}

#endif
--------------------------------------------------View the Solution FREE for 30 Days

how linux system call works?

check it out, so cool

http://www.ibm.com/developerworks/linux/library/l-system-calls/index.html

Thursday, October 15, 2009

stupid madwifi virtual device handling

Madwifi athX virtual devices always send TX_OK to networking kernel,

look into ieee80211_hardstart function at net80211/ieee80211_output.c

at the end of the function, it returns NETDEV_TX_OK.

We have to change it to check whether ieee80211_paranet_queue_xmit is succeeded or not and return the result.
Be sure not to free the skb before returning NETDEV_TX_BUSY.
Network kernel will try to free the skb AGAIN!!

Linux network kernel does not allow virtual device is busy!!

http://lxr.linux.no/linux+v2.6.26.6/net/core/dev.c#L1733

1733                                rc = 0;
1734                                if (!dev_hard_start_xmit(skb, dev)) {
1735                                        HARD_TX_UNLOCK(dev); 
1736                                        goto out; 
1737                                } 
1738                        } 
1739                        HARD_TX_UNLOCK(dev); 
1740                        if (net_ratelimit()) 
1741                                printk(KERN_CRIT "Virtual device %s asks to " 
1742                                       "queue packet!\n", dev->name);

if dev_hard_start_xmit failed, it does not report the reason to upper layer.
Look, rc is zero (which means TX_OK),

How about 
rc = dev_hard_start_xmit(), to report that the virtual device is going crazy ?

Saturday, October 10, 2009

Simply print stack trace...

lookup

warn_on_slowpath()

or you can use dump_stack()

Debugging linux kernel

1 Debugging Linux Kernel Lockup / Panic / Oops

Here are some notes on how to debug Linux kernel lockups – both "hard lockups" and "soft lockups" – and other panic, BUG, and oops situations. I am not an expert in this, but I figured incomplete information was better than no information, so here we go:

1. One way of confirming that you are the victim of a lockup is to note that the keyboard “caps lock” light does not respond to the “caps lock” key. Similarly the the “num lock” light won’t respond to the “num lock” key. Furthermore, the machine will not respond to ctrl-alt-delete.

Some people take this symptom as their definition of a hard lockup ... but beware that there is a situation that the kernel calls a soft lockup that exhibits the same symptom.

One way a soft lockup can occur is when the machine goes into a loop with interrupts turned off. This commonly happens if a device driver uses spinlocks improperly.

2. It is good to enable "Detect Soft Lockup" in the kernel. I believe everybody should do this, routinely, even if they are not expecting kernel bugs. To enable this:
 make menuconfig          \--> Kernel Hacking            \--> Detect Soft Lockups 

and then of course recompile your kernel, install the newly compiled kernel, and reboot.

For slightly more information, see the associated with this configuration option. As it says (in part) there:

Say Y here to enable the kernel to detect "soft lockups", which are bugs that cause the kernel to loop in kernel mode for more than 10 seconds, without giving other tasks a chance to run.

When a soft-lockup is detected, the kernel will print the current stack trace (which you should report), but the system will stay locked up. This feature has negligible overhead.

3. If there is a kernel “panic” or “BUG” or “oops”, you will want to capture the stack trace.

In some smallish subset of cases, the stack trace will be saved in the log files, but you should not count on this.

Far and away the best way to do this is to set up a “serial console”. That is, you arrange for console i/o (including oops messages) to appear on a serial port.

Getting this to work requires the following steps:

        make menuconfig          \--> Device Drivers            \--> Character devices              \--> Serial drivers                \--> Console on 8250/16550 and compatible serial port 

Then, in your /boot/grub/menu.lst file, add a boot option, namely

          console=ttyS0,115200 

or more explicitly, you need a grub stanza something like this:

     title Linux (serial console)         root (hd0,2)         kernel /boot/vmlinuz-2.6.99 ro root=/dev/sda3 console=ttyS0,115200 console=tty0 

Here tty0 refers to “the” PC screen (i.e. the one hooked to “the” graphics card via the VGA interface or some such). Meanwhile, ttyS0 refers to the lowest-numbered serial line. Note that ttyS0 is what Microsoft calls com1, and ttyS1 is what they call com2, et cetera; the MS numbers are systematically one unit higher.

You are not required to explicitly specify the baudrate (115200) of the serial line, but I recommend you do so. Of course you are free to use another serial line such as ttyS1 if you prefer. In any case, you must use the correct capitalization (capital S). Note that you can specify more than one console=... option, as in the example above. If you specify none, you get tty0 by default. If you specify only ttyS0, you get that instead of tty0. If you want both, you must specify both.

Tangential remark: Choosing to log kernel messages to the serial port is independent of choosing to permit logins on that serial port; you can choose either or both or neither.

If you choose both, it allows you to administer a system that has no screen at all.

Edit /etc/inittab to tell init to spawn a getty on the chosen serial line. I recommend you leave at least one runlevel where the getty is not spawned, for convenience if you ever need to use that serial port for something else. You may also need to edit /etc/securetty if you want to permit root logins on the serial line.

If you want to interact with the grub menu via the serial line, you must reconfigure grub accordingly. See the grub info pages. (You can skip this task if you are content to let grub boot the default kernel without interaction, which is often the case. Just don’t make a mistake with your grub configuration, or you’ll be locked out until you hook up a screen.)

Then of course you must hook up a serial cable from your computer (#1) to some other computer (#2). We assume computer #2 will remain running even if/when computer #1 crashes. On computer #2, run some communication program such as Kermit to allow you to talk to the serial line, and log the traffic to a disk file.

Computer #2 doesn’t need to be a Linux box. If it is a windows box, you can install Kermit-for-windows, or just use the built-in “hyperterm” application to make the connection and log the traffic.

As for the cable itself, you need “null modem” functionality. This just involves crossing a couple of wires. In many cases, if the cable has female connectors on both ends, it will have this functionality built in. In particular, a so-called LapLink cable has null-modem functionality built in. Conversely, if the cable looks like an extension cord (male on one end, female on the other) it most likely does not have null-modem functionality, and you will need a separate dongle (both to perform the sex-change operation and to cross the required wires).

To test that it is working, try something like

       echo "Hi there." > /dev/console 

and verify that the message is seen by computer #2.

If you have two computers, you can use each to ride herd on the other. All you need is two cables. Just use ttyS0 as the console on each one, and monitor it with ttyS1 on the other. Presumably they won’t both crash at the same time. If you have a large number of computers, you can connect them in a big daisy chain: A→B→C→D→E→A. If you have an even number of machines, you might consider connecting them in pairs, but the daisy chain is just as easy, and isn’t limited to even numbers. If machine N crashes, you can ssh to machine N+1 (via its ethernet interface) to collect the logged information; we don’t need to rely on the serial links for all of our communication.

4. If you are debugging Linux device drivers, additional steps are needed. The problem is that the normal Linux serial-port driver is interrupt driven, so if your driver crashes with the interrupts off, you’ll never see the stack trace on the serial console. The fix for this is simple:
 make menuconfig          \--> Kernel Hacking            \--> Early printk 

The point here is that by selecting this option, you get a non-interrupt-dependent printk (not just an “early” printk). This trick is not very well documented or widely known, so be glad that somebody told you about it.

There are some mild downsides to the early printk option; see the menuconfig for this option for details.

5. I’m not entirely sure what the kernel calls “hard” lockup. I suppose it is any lockup so horrible that it cannot be detected by the aforementioned soft lockup detector.

The simplest way to escape from a hard lockup and get a stack trace is by means of a watchdog timer. For info on watchdog timers, read /usr/src/linux/Documentation/watchdog/*.txt.

If you are running on a system that has an Intel 82801 “I/O Controller Hub” chip (which includes most of the reasonably modern Intel-based systems) then life is simple: you can use the TCO timer and route it to the processor’s NMI line (Non-Maskable Interrupt).

To make this happen:

 make menuconfig           \--> Device Drivers             \--> Character devices               \--> Watchdog Cards                 \--> Intel i8xx TCO Timer/Watchdog                 \--> Intel TCO Timer/Watchdog 

Make it a module. Load it with modprobe iTCO-wdt.

Note that in some older kernels the option was named differently
 make menuconfig           \--> Device Drivers             \--> Character devices               \--> Watchdog Cards                 \--> Intel i8xx TCO Timer/Watchdog 
The module was loaded with modprobe i8xx-tco.

You can tickle it with the simple userspace program in section 2, or the even simpler program mentioned in /usr/src/linux/Documentation/watchdog/watchdog.txt. That program is advertised as “Example Watchdog Driver” but it’s not a driver in the usual sense of the word; it’s really an “Example Watchdog Daemon” or something like that.

Alternatively, you can tickle it using something like echo > /dev/watchdog every so often. Use echo -n V > /dev/watchdog to make the watchdog stop watching (so you can stop tickling, without causing a reboot).

If you don’t have an 82801 chip, you’ll have to buy one of the hardware cards described in the aforementioned watchdog.txt file.

6. There is also a thing called “softdog” aka “soft watchdog” aka “software watchdog” ... but I’ve never figured out what it’s good for.
  • For soft lockups, it is not needed; the aforementioned soft lockup detector works fine.
  • For hard lockups, it is not effective.
  • I guess you could use it to check the health of some critical userspace application ... but in this case I would think that userspace timers would be a more appropriate solution.

If you’re still interested, you can find it at:

 make menuconfig           \--> Device Drivers             \--> Character devices               \--> Watchdog Cards                 \--> Software watchdog 

7. Another way of performing the “watchdog” task is via an external power controller, aka controlled power strip. An example is the RPC-S6, which has six independently-controlled power outlets, and accepts control signals via a serial port. There are similar products that accept control signals via a parallel port or via IP.

There are at least two ways to proceed:

  • You can have two or more power controllers, such that power to each machine comes from a strip controlled by some other machine.
  • Suppose you have only one power controller, and it is controlled by machine A. You can set up a watchdog function (aka heartbeat function) on one of the outlets, and use that outlet to power machine A. That means that if machine A ever hangs, the power controller will cycle power to that outlet, causing a reboot.

    Of course if machine A is not hung, you have programmatic control of all the machines plugged into the power controller. This includes control of machine A itself. Beware that any command to power down machine Ais irreversible, unless the same command brings the power back up later.

2 Example Watchdog Daemon Program

#include \
#include \
#include \
#include \

#include

typedef void (*sighandler_t)(int);

int fd;

void handler(int sig) {
write(fd, "V", 1);
fprintf(stdout, "Bye (%d).\n", sig);
exit(0);
}

void inst(const int sig){
sighandler_t rslt = signal(sig, handler);
if (rslt == SIG_ERR) {
fprintf(stderr, "Could not set up signal handler: ");
perror(0);
exit(1);
}
}

int main(int argc, const char *argv[]) {

inst(SIGHUP); // hangup
inst(SIGINT); // often tied to ^C
inst(SIGTERM); // default for kill command

fd = open("/dev/watchdog", O_WRONLY);
if (fd == -1) {
fprintf(stderr, "Could not open /dev/watchdog: ");
perror(0);
// exit(1);
}
while (1) {
write(fd, "\0", 1);
fsync(fd);
sleep(10);
}
}

3  References

1.
Glenn Turner “Remote Serial Console HOWTO” http://www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/