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