More news
[yaz-moved-to-github.git] / ziffy / hooks.c
1 /*
2  * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
3  * hooks.c - a TCP/IP protocol filter for ziffy
4  *
5  * Copyright (c) 1998-2001 R. Carbone <rocco@ntop.org>
6  * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22
23 #define _BSD_SOURCE
24
25
26 /*
27  * Operating System include files
28  */
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33
34 #include <netdb.h>
35 #include <arpa/inet.h>
36
37 #if HAVE_NET_IF_H
38 #include <net/if.h>
39 #endif
40
41 #if HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44
45 #if HAVE_NETINET_IF_ETHER_H
46 #include <netinet/if_ether.h>
47 #endif
48
49 #if HAVE_NETINET_IN_SYSTM_H
50 #include <netinet/in_systm.h>
51 #endif
52
53 #include <netinet/ip.h>
54 #include <netinet/tcp.h>
55
56 #include "pcap.h"                   /* Packet Capture Library */
57
58 #include "apdu.h"
59
60 void fmemdmp (FILE * fd, char * ptr, int size, char * text);
61
62
63 /* external */
64 extern int dlt;
65
66
67 /*
68  * to allow a pretty-print of lower-layers address I save
69  * relevant pointers to all the protocol data units in global variables,
70  * rather than pass them across function calls.
71  * So, for example, if someone is interested in the paired source and
72  * destination IP addressed, they can be easily accessed by global 'ip' pointer.
73  */
74
75
76 /*
77  * hooks to the known protocols in the ethernet packets
78  */
79 static struct ether_header * e = NULL;
80 static struct ip * ip          = NULL;
81 static struct tcphdr * tcp     = NULL;
82 extern u_char * z3950;
83
84 /*
85  * sizes of the known protocols in the ethernet packets
86  */
87 static int eth_size   = 0;
88 static int eth_hlen   = 0;
89 static int ip_size    = 0;
90 static int ip_hlen    = 0;
91 static int tcp_size   = 0;
92 static int tcp_hlen   = 0;
93 extern int z3950_size;
94
95
96 char * srchost (void)
97 {
98   static char buf [256];  /* should be enough for humans !!! */
99
100   struct hostent * host = NULL;
101
102   if (aflag)
103     host = gethostbyaddr ((char *) & ip -> ip_src, sizeof (ip -> ip_src), AF_INET);
104
105   sprintf (buf, "%s", host ? host -> h_name : inet_ntoa (ip -> ip_src));
106   return (buf);
107 }
108
109
110 int srcport (void)
111 {
112   return ((int) ntohs (tcp -> th_sport));
113 }
114
115
116 char * dsthost (void)
117 {
118   static char buf [256];  /* should be enough for humans !!! */
119
120   struct hostent * host = NULL;
121
122   if (aflag)
123     host = gethostbyaddr ((char *) & ip -> ip_dst, sizeof (ip -> ip_dst), AF_INET);
124
125   sprintf (buf, "%s", host ? host -> h_name : inet_ntoa (ip -> ip_dst));
126   return (buf);
127 }
128
129
130 int dstport (void)
131 {
132   return ((int) ntohs (tcp -> th_dport));
133 }
134
135
136 /*
137  * stolen from the addrtoname.c in tcpdump
138  */
139 static char hex [] = "0123456789abcdef";
140
141 static char * etheraddr_string (u_char * e)
142 {
143   static char buf [sizeof ("00:00:00:00:00:00")];
144
145   int i;
146   int j;
147   char * p;
148
149   strcpy (buf, "00:00:00:00:00:00");
150
151   /*
152    * hacked to manage DLT_NULL
153    */
154   if (! e)
155     return (buf);
156
157   p = buf;
158   if ((j = * e >> 4) != 0)
159     * p ++ = hex [j];
160   * p ++ = hex [* e ++ & 0xf];
161   for (i = 5; -- i >= 0; )
162     {
163       * p ++ = ':';
164       if ((j = * e >> 4) != 0)
165         * p ++ = hex [j];
166     * p ++ = hex [* e ++ & 0xf];
167     }
168   * p = '\0';
169   return (buf);
170 }
171
172
173 /*
174  * Parse the incoming Ethernet Packet and set hooks to all pertinent data.
175  *
176  * 'h' is the pointer to the packet header (independent from interfaces)
177  * 'p' is the pointer to the packet data
178  *
179  * Warning: I really want libpcap to give me aligned packets
180  */
181 z3950apdu * pduhook (const struct pcap_pkthdr * h, const u_char * p)
182 {
183   static unsigned long ethno = 0;  /* # of ethernet packets received by the decoder */
184   static unsigned long ipno = 0;   /* # of IP packets received by the decoder */
185   static unsigned long tcpno = 0;  /* # of TCP packets received by the decoder */
186
187   u_char * q;
188
189   z3950apdu * apdu = NULL;
190
191   /*
192    * Ethernet Protocol
193    */
194   e = (struct ether_header *) p;
195
196   /*
197    * Ethernet sizes
198    *
199    * The header is only 4 bytes long in case of no link-layer encapsulation (DLT_NULL).
200    * It contains a network order 32 bit integer that specifies the family, e.g. AF_INET
201    */
202   eth_size = h -> len;
203   eth_hlen = dlt == DLT_NULL ? 4 : sizeof (struct ether_header);
204
205   ++ ethno;
206
207   if (ethflag)
208     printf ("ETHER:  ----- Ether Header -----\n"),
209       printf ("ETHER:\n"),
210       printf ("ETHER:  Packet %ld arrived at %s\n", ethno, timestamp (& h -> ts, ABS_FMT)),
211       printf ("ETHER:  Total size  = %d : header = %d : data = %d\n",
212               eth_size, eth_hlen, eth_size - eth_hlen),
213       printf ("ETHER:  Source      = %s\n",
214               etheraddr_string (dlt == DLT_NULL ? NULL : (u_char *) & e -> ether_shost)),
215       printf ("ETHER:  Destination = %s\n",
216               etheraddr_string (dlt == DLT_NULL ? NULL : (u_char *) & e -> ether_dhost)),
217       fflush (stdout),
218       fmemdmp (stdout, (char *) e, eth_size, "Ethernet Packet");
219
220   /*
221    * Process only IP packets (or loopback packets when testing at home sweet home)
222    */
223   if (dlt == DLT_NULL || ntohs (e -> ether_type) == ETHERTYPE_IP)
224     {
225       /*
226        * IP Protocol
227        */
228       ip = (struct ip *) (p + eth_hlen);
229
230       /*
231        * IP sizes
232        *
233        * ip->ip_hl*4        = size of the IP (Header Only)
234        * ntohs (ip->ip_len) = size of the IP (Full Packet)
235        *            ip_size = eth_size - eth_hlen (better IMO)
236        */
237       ip_size = eth_size - eth_hlen;
238       ip_hlen = ip -> ip_hl * 4;
239
240       ++ ipno;
241
242       if (ipflag)
243         printf ("IP:     ----- IP Header -----\n"),
244           printf ("IP:\n"),
245           printf ("IP:     Packet %ld arrived at %s\n", ipno, timestamp (& h -> ts, ABS_FMT)),
246           printf ("IP:     Total size  = %d : header = %d : data = %d\n",
247                   ip_size, ip_hlen, ip_size - ip_hlen),
248           printf ("IP:     Source      = %s\n", inet_ntoa (ip -> ip_src)),
249           printf ("IP:     Destination = %s\n", inet_ntoa (ip -> ip_dst)),
250           fflush (stdout);
251
252 #if (0)
253       fmemdmp (stdout, (char *) ip, ip_size, "IP Packet");
254 #endif
255
256       /*
257        * i am looking for Z39.50 APDUs over TCP/IP. so...
258        */
259       if (ip -> ip_p == IPPROTO_TCP)
260         {
261           /*
262            * TCP Protocol
263            */
264           q = (u_char *) ip + ip_hlen;
265           tcp = (struct tcphdr *) q;
266
267           /*
268            * TCP sizes
269            *
270            * tcp->th_off*4 = size of the TCP (Header Only)
271            */
272           tcp_size = ip_size - ip_hlen;
273           tcp_hlen = tcp -> th_off * 4;
274
275           ++ tcpno;
276
277           if (tcpflag)
278             printf ("TCP:    ----- TCP Header -----\n"),
279               printf ("TCP:\n"),
280               printf ("TCP:    Packet %ld arrived at %s\n", tcpno, timestamp (& h -> ts, ABS_FMT)),
281               printf ("TCP:    Total size  = %d : header = %d : data = %d\n",
282                       tcp_size, tcp_hlen, tcp_size - tcp_hlen),
283               printf ("TCP:    Source      = %d\n", ntohs (tcp -> th_sport)),
284               printf ("TCP:    Destination = %d\n", ntohs (tcp -> th_dport)),
285               fflush (stdout),
286               fmemdmp (stdout, (char *) tcp, tcp_size, "TCP Packet");
287
288           /*
289            * Application Protocol
290            * (time to play with Z39.50 APDUs here)
291            */
292           z3950 = (u_char *) e + eth_hlen + ip_hlen + tcp_hlen;
293
294           /*
295            * Higher Protocol Packet Size
296            */
297           z3950_size = tcp_size - tcp_hlen;
298
299           apdu = parseable (z3950, z3950_size);
300
301           if (tcpflag && apdu)
302             printf ("TCP:    ----- TCP Header -----\n"),
303               printf ("TCP:\n"),
304               printf ("TCP:    Packet %ld arrived at %s\n", tcpno, timestamp (& h -> ts, ABS_FMT)),
305               printf ("TCP:    Total size  = %d : header = %d : data = %d\n",
306                       tcp_size, tcp_hlen, tcp_size - tcp_hlen),
307               printf ("TCP:    Source      = %d\n", ntohs (tcp -> th_sport)),
308               printf ("TCP:    Destination = %d\n", ntohs (tcp -> th_dport)),
309               fflush (stdout),
310               fmemdmp (stdout, (char *) tcp, tcp_size, "TCP Packet");
311
312
313           return (apdu);
314         }
315     }
316   return (NULL);
317 }