Datalink Access Datalink Access Provides access to the datalink layer for an application Capabilities Ability to watch the packets received by the datalink layer Run certain programs as applications instead of kernel. Ex: RARP Access Methods 3 common methods BSD Packet Filter (BPF) SVR4 Datalink Provider Interface (DLPI) Linux SOCK_PACKET interface Libpcap library Publicly available packet capture library Works with all the above three methods. Writing programs with this makes them OS independent BSD Packet Filter (BPF) Each datalink driver calls BPF right before a packet is transmitted Right after a packet is received Filter capability Each application opens BPF device Can load its own filter Applied by BPF to each packet Filter can be as detailed as “only TCP segments to or from 80, only SYN, FIN or RST BSD Packet Filter (BPF) BSD Packet Filter (BPF) Three techniques to reduce overhead: Filters within kernel. Avoids data copy into user appl. Only a portion of each packet is copied. (14+40+20+22=96 bytes) BPF buffers the data. It is copied to appl buffer only when full or read timeout expires. Datalink Provider Interface (DLPI) Datalink Provider Interface (DLPI) Similar to BPF Differences: Filter implementation in BPF is 3 to 20 times faster than DLPI. Directed acyclic control flow graph an boolean expression tree. BPF always make the filtering decision before copying the packet. DLPI may first copy the packet to pfmod and then make the decision. Linux Two methods: Socket of type:SOCK_PACKET Socket of family: PF_PACKET Third argument must specify the frame type. PF_PACKET: Type is SOCK_RAW to receive complete link layer packet. Socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); Linux Differences with BPF and DLPI: Provides no kernel buffering. Filtering is avaialble only with PF_PACKET. Multiple frames can’t be buffered together. So it increase no. of sys calls. libpcap Provides implementation independent access to the underlying packet capture facility. Libpcap example int main(int argc, char *argv[]) { pcap_t *handle; char *dev; char errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program fp; char filter_exp[] = "port 23"; bpf_u_int32 mask; bpf_u_int32 net; struct pcap_pkthdr header; const u_char *packet; /* /* /* /* /* /* /* /* /* Session handle */ The device to sniff on */ Error string */ The compiled filter */ The filter expression */ Our netmask */ Our IP */ The header that pcap gives us */ The actual packet */ /* Define the device */ dev = pcap_lookupdev(errbuf); if (dev == NULL) { fprintf(stderr, "Couldn't find default device: %s\n", errbuf); return(2); } Libpcap example[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", somedev, errbuf); return(2); } /* Compile and apply the filter */ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2); } Libpcap example[2] if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2); } /* Grab a packet */ packet = pcap_next(handle, &header); /* Print its length */ printf(“Got a packet with length of [%d]\n", header.len); /* And close the session */ pcap_close(handle); return(0); } Libpcap example[2]