Sunteți pe pagina 1din 34

Raw Sockets

(+ other)
UNPv1 - Stevens, Fenner, Rudoff
Linux Socket Programming - Walton

Other
Readv ( ) and writev ( )
Read or write data into multiple buffers
Connection-oriented.

Recvmsg ( ) and sendmsg ( )


Most general form of send and receive.
Supports multiple buffers and flags.
Connectionless

cs423 - cotter

readv( ) and writev( )


ssize_t writev ( int filedes, const struct iovec *iov, int iovcnt);
ssize_t readv ( int filedes, const struct iovec *iov, int iovcnt);

filedes socket identifier


iov pointer to an array of iovec structures
iovcnt number of iovec structures in the array (16 < iovcnt: Linux 1024)
Return value is # of bytes transferred or -1 or error

struct iovec {
void * iov_base; // starting address of buffer
size_t iov_len; // size of buffer
};

cs423 - cotter

writev( ) example:

Write a packet that contains multiple separate data elements


2 character opcode
2 character block count
512 character data block

char opcode[2] = 03;


char blkcnt[2] = 17;
char data[512] = This RFC specifies a standard ;
struct iovec iov[3];
iov[0].iov_base = opcode;
iov[0].iov_len = 2;
iov[1].iov_base = blkcnt;
iov[1].iov_len = 2;
iov[2].iov_base = data;
iov[3].iov_len = 512;
writev (sock, &iov, 3);

cs423 - cotter

writev( ) example:

writev (sock, &iov, 3);


cs423 - cotter

recvmsg ( ) and sendmsg ( )


ssize_t recvmsg (int sock, struct msghdr *msg,
int flags);
ssize_t sendvmsg (int sock, struct msghdr *msg,
int flags);
Sock Socket identifier
Msg struct msghdr that includes message to be
sent as well as address and msg_flags
Flags sockets level flags
Return value is # of bytes transferred or -1 or error
cs423 - cotter

Sockets level flags


Flag

Description

MSG_DONTR Bypass routing table lookup


OUTE
Only this operation is
MSG_DONTW
nonblocking
AIT
Peek at incoming message
MSG_PEEK
Wait for all the data
MSG_WAITAL Send or receive out-of-band
L
data
MSG_OOB
cs423 - cotter

REC
V
*
*
*
*

SEN
D
*
*
*

Struct msghdr
struct msghdr {
void
*msg_name; // protocol address
socklen_t msg_namelen
// size of protocol address
struct iovec *msg_iov // scatter / gather array
int
msg_iovlen //# of elements in msg_iov
void
*msg_cntrl // cmsghdr struct
socklen_t msg_cntrllen // length of msg_cntrl
int
msg_flags // flags returned by recvmsg
};
cs423 - cotter

Msg_flags
Flag

Returned by
recvmsg msg_flags

MSG_EOR
MSG OOB

*
*

MSG_BCAST
MSG_MCAST
MSG_TRUNC
MSG_CTRUNC
MSG_NOTIFICATION

*
*
*
*
*

cs423 - cotter

recvmsg example (ICMP)


char
recvbuf[BUFSIZE];
char
controlbuf[BUFSIZE];
struct msghdr msg;
struct iovec iov;
sockfd = socket (PF_INET, SOCK_RAW, pr->icmpproto);
iov.iov_base = recvbuf;
iov.iov_len = sizeof(recvbuf);
msg.msg_name = sin; //sockaddr struct, for senders IP & port
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = controlbuf;
for ( ; ; ) {
msg.msg_namelen =sizeof(sin);
msg.msg_controllen = sizeof(controlbuf);
n = recvmsg(sockfd, &msg, 0);
:
:
cs423 - cotter

10

What are (standard) sockets?


1. ?
2. ?
3. ?

Limitations
1. ?
2. ?
3. ?
cs423 - cotter

11

What are Raw Sockets?


1. A way to pass information to network
protocols other than TCP or UDP (e.g.
ICMP and IGMP)
2. A way to implement new IPv4 protocols
3. A way to build our own packets (be careful
here)

cs423 - cotter

12

Why Would We Use Them?


Allows us to access packets sent over protocols
other than TCP / UDP
Allows us to process IPv4 protocols in user
space
Control, speed, troubleshooting

Allow us to implement new IPv4 protocols


Allows us to control the IP header
Control option fields (beyond setsockopt() )
Test / control packet fragmentation
cs423 - cotter

13

Limitations?

Reliability Loss
No Ports
Nonstandard communication
No Automatic ICMP
Raw TCP / UDP unlikely
Requires root / admin

cs423 - cotter

14

OS Involvement in Sockets
User Space
Socket App

Kernel Space
Linux

TCP/IP Stack

Socket ( AF_INET,
SOCK_STREAM,
IPPROTO_TCP)

Identify
Socket Type

TCP

Socket ( AF_INET,
SOCK_RAW,
IPPROTO_ICMP)

Identify
Socket Type

IP

Socket ( AF_PACKET,
SOCK_RAW,
htons(ETH_P_IP))
cs423 - cotter

Identify
Socket Type

Ethernet
15

Normal Socket Operation (TCP)


Create a socket
s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)

Bind to a port (optional)


Identify local IP and port desired and create data structure
bind (s, (struct sockaddr *) &sin, sizeof(sin))

Establish a connection to server


Identify server IP and port
connect (s, (struct sockaddr *) &sin, sizeof(sin))

Send / Receive data


Place data to be send into buffer
recv (s, buf, strlen(buf), 0);
cs423 - cotter

16

Normal Socket Operation (TCP)


User Space

Kernel Space

Socket App

Linux
Create socket

socket ( )

Protocol
TCP

OK
Bind to local port:
Connect to remote port

connect( )

TCP, IP, Internet

OK
Pass data thru local
stack to remote port

send( )

TCP, IP, Internet

OK

cs423 - cotter

17

Raw Sockets Operation (ICMP)


Create a socket
s = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP)

Since there is no port, there is no bind *


There is no TCP, so no connection *
Send / Receive data
Place data to be sent into buffer
sendto (s, buf, strlen(buf), 0, addr, &len);

* More later
cs423 - cotter

18

Raw Sockets Operation (ICMP)


User Space

Kernel Space

Socket App

Linux
Create socket

socket ( )

Protocol
ICMP

OK
Pass data thru local
stack to remote host

sendto( )

IP, Internet

OK

cs423 - cotter

19

Create a Raw Socket


s = socket (AF_INET, SOCK_RAW, protocol)
IPPROTO_ICMP, IPPROTO_IP, etc.

Can create our own IP header if we wish


const int on = 1;
setsockopt (s, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on));

Can bind
Since we have no port, the only effect is to associate a local IP
address with the raw socket. (useful if there are multiple local IP
addrs and we want to use only 1).

Can connect
Again, since we have no TCP, we have no connection. The only
effect is to associate a remote IP address with this socket.

cs423 - cotter

20

Raw Socket Output


Normal output performed using sendto or sendmsg.
Write or send can be used if the socket has been connected

If IP_HDRINCL not set, starting addr of the data (buf) specifies


the first byte following the IP header that the kernel will build.
Size only includes the data above the IP header.

If IP_HDRINCL is set, the starting addr of the data identifies


the first byte of the IP header.
Size includes the IP header
Set IP id field to 0 (tells kernel to set this field)
Kernel will calculate IP checksum

Kernel can fragment raw packets exceeding outgoing MTU


cs423 - cotter

21

Raw Socket Input


Received TCP / UDP NEVER passed to a raw socket.
Most ICMP packets are passed to a raw socket
(Some exceptions for Berkeley-derived implementations)

All IGMP packets are passed to a raw socket


All IP datagrams with a protocol field that the kernel does
not understand (process) are passed to a raw socket.
If packet has been fragmented, packet is reassembled
before being passed to raw socket

cs423 - cotter

22

Conditions that include / exclude


passing to specific raw sockets
If a nonzero protocol is specified when raw
socket is created, datagram protocol must
match
If raw socket is bound to a specific local
IP, then destination IP must match
If raw socket is connected to a foreign IP
address, then the source IP address must
match
cs423 - cotter

23

Ping Overview
This example modified from code by Walton (Ch 18)
Very simple program that uses ICMP to send a ping to
another machine over the Internet.
Provides the option to send a defined number of packets
(or will send a default 25).
We will build an ICMP packet (with a proper header,
including checksum) that will be updated each time we
send a new packet.
We will display the raw packet that is received back from
our destination host and will interpret some of the data.
(Output format is different from standard ping)
cs423 - cotter

24

ICMP Packet header


struct icmphdr {
u_int8_t type
u_int8_t code
u_int16_t checksum
u_int16_t id
u_int16_t sequence
};

// ICMP message type (0)


// ICMP type sub-code (0)
E306, etc.
// echo datagram id (use pid)
// echo seq # 1, 2, 3, etc.

Packet body:
0123456789:;<=>?B
cs423 - cotter

25

myNuPing.c (overview)
Global Declarations
Struct packet { }, some variables

unsigned short checksum (void *b, int len)


Calculate checksum for ICMP packet (header and data)

void display (void *buf, int bytes)


Format a received packet for display.

void listener (void)


Separate process to capture responses to pings

void ping (struct sockaddr_in *addr)


Create socket and send out pings 1/sec to specified IP addr

int main (int count, shar *strings[ ])


Test for valid instantiation, create addr structure
Fork a separate process (listener) and use existing process for ping
cs423 - cotter

26

#defines and checksum calc


#define PACKETSIZE 64
struct packet {
struct icmphdr hdr;
char msg[PACKETSIZE-sizeof(struct icmphdr)];
};
int pid=-1;
int loops = 25;
struct protoent *proto=NULL;
unsigned short checksum(void *b, int len) {
unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;
for ( sum = 0; len > 1; len -= 2 )
sum += *buf++;
if ( len == 1 )
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
cs423 - cotter

27

display - present echo info


void display(void *buf, int bytes) {
int i;
struct iphdr *ip = buf;
struct icmphdr *icmp = buf+ip->ihl*4;

printf("----------------\n");
for ( i = 0; i < bytes; i++ )
{
if ( !(i & 15) ) printf("\n%04X: ", i);
printf("%02X ", ((unsigned char*)buf)[i]);
}
printf("\n");
printf("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d src=%s ",
ip->version, ip->ihl*4, ntohs(ip->tot_len), ip->protocol,
ip->ttl, inet_ntoa(ip->saddr));
printf("dst=%s\n", inet_ntoa(ip->daddr));
if ( icmp->un.echo.id == pid )
{
printf("ICMP: type[%d/%d] checksum[%d] id[%d] seq[%d]\n",
icmp->type, icmp->code, ntohs(icmp->checksum),
icmp->un.echo.id, icmp->un.echo.sequence);
}

cs423 - cotter

28

Listener - separate process to listen


for and collect messagesvoid listener(void) {
int sd, i;
struct sockaddr_in addr;
unsigned char buf[1024];
sd = socket(PF_INET, SOCK_RAW, proto->p_proto);
if ( sd < 0 )
{
perror("socket");
exit(0);
}
for (i = 0; i < loops; i++)
{
int bytes, len=sizeof(addr);
bzero(buf, sizeof(buf));
bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *) &addr,
&len);
if ( bytes > 0 )
display(buf, bytes);
else
perror("recvfrom");
}
exit(0);
}
cs423 - cotter

29

ping - Create message and send it


void ping(struct sockaddr_in *addr)
{
const int val=255;
int i, j, sd, cnt=1;
struct packet pckt;
struct sockaddr_in r_addr;
sd = socket(PF_INET, SOCK_RAW, proto->p_proto);
if ( sd < 0 )
{
perror("socket");
return;
}
if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
perror("Set TTL option");
if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
perror("Request nonblocking I/O");
cs423 - cotter

30

ping (cont)
for (j = 0; j < loops; j++)
{ // send pings 1 per second
int len=sizeof(r_addr);
printf("Msg #%d\n", cnt);
if ( recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr *)&r_addr, &len) > 0 )
printf("***Got message!***\n");
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = pid;
for ( i = 0; i < sizeof(pckt.msg)-1; i++ )
pckt.msg[i] = i+'0';
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = cnt++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
if (sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr *) addr, sizeof(*addr)) <= 0)
perror("sendto");
sleep(1);
}
}
cs423 - cotter

31

myNuPing.c main()

int main(int count, char *argv[]) {


struct hostent *hname;
struct sockaddr_in addr;
loops = 0;
if ( count != 3 )
{
printf("usage: %s <addr> <loops> \n", argv[0]);
exit(0);
}
if (count == 3) // WE HAVE SPECIFIED A MESSAGE COUNT
loops = atoi(argv[2]);
if ( count > 1 )
{
pid = getpid();
proto = getprotobyname("ICMP");
hname = gethostbyname(argv[1]);
bzero(&addr, sizeof(addr));
addr.sin_family = hname->h_addrtype;
addr.sin_port = 0;
addr.sin_addr.s_addr = *(long*)hname->h_addr;
if ( fork() == 0 )
listener();
else
ping(&addr);
wait(0);
}
else
printf("usage: myping <hostname>\n");
return 0;
} cs423 - cotter

32

Ping Output
[root]# ./myNuPing 134.193.12.34 2
Msg #1
---------------0000: 45 00 00 54 CC 38 40 00 80 01 1F BE 86 12 34 56
0010: 86 12 34 57 00 00 E4 06 DF 07 01 00 30 31 32 33
0020: 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43
0030: 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
0040: 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63
0050: 64 65 66 00
IPv4: hdr-size=20 pkt-size=84 protocol=1 TTL=128 src=134.193.12.35 dst=134.193.12.34
ICMP: type[0/0] checksum[58374] id[2015] seq[1]
Msg #2
***Got message!***
---------------0000: 45 00 00 54 CC 39 40 00 80 01 1F BD 86 12 34 56
0010: 86 12 34 57 00 00 E3 06 DF 07 02 00 30 31 32 33
0020: 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43
0030: 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
0040: 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63
0050: 64 65 66 00
IPv4: hdr-size=20 pkt-size=84 protocol=1 TTL=128 src=134.193.12.35 dst=134.193.12.34
ICMP: type[0/0] checksum[58118] id[2015] seq[2]
[root]#

cs423 - cotter

33

Summary
Raw Sockets allow access to Protocols other than
the standard TCP and UDP
Performance and capabilities may be OS
dependent.
Some OSs block the ability to send packets that originate
from raw sockets (although reception may be permitted).

Raw sockets remove the burden of the complex


TCP/IP protocol stack, but they also remove the
safeguards and support that those protocols provide

cs423 - cotter

34

S-ar putea să vă placă și