]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/zip.c
implemented config.h
[netatalk.git] / etc / atalkd / zip.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved. See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/syslog.h>
15 #include <sys/socket.h>
16 #include <sys/ioctl.h>
17 #include <sys/time.h>
18 #include <net/if.h>
19 #include <net/route.h>
20 #include <netatalk/endian.h>
21 #include <netatalk/at.h>
22
23 #ifdef __svr4__
24 #include <sys/sockio.h>
25 #endif __svr4__
26
27 #include <atalk/ddp.h>
28 #include <atalk/zip.h>
29 #include <atalk/atp.h>
30 #include <atalk/util.h>
31
32 #include "atserv.h"
33 #include "interface.h"
34 #include "gate.h"
35 #include "zip.h"
36 #include "rtmp.h"
37 #include "list.h"
38 #include "multicast.h"
39
40 struct ziptab   *ziptab = NULL, *ziplast = NULL;
41
42 static int zonecheck( rtmp, iface )
43     struct rtmptab      *rtmp;
44     struct interface    *iface;
45 {
46     struct list         *l;
47     struct ziptab       *czt, *zt;
48     int                 cztcnt, ztcnt;
49
50     if (( iface->i_flags & IFACE_SEED ) == 0 ) {
51         return( 0 );
52     }
53
54     for ( cztcnt = 0, czt = iface->i_czt; czt; czt = czt->zt_next, cztcnt++ ) {
55         for ( l = rtmp->rt_zt; l; l = l->l_next ) {
56             zt = (struct ziptab *)l->l_data;
57             if ( czt->zt_len == zt->zt_len &&
58                     !strndiacasecmp( czt->zt_name, zt->zt_name, czt->zt_len )) {
59                 break;
60             }
61         }
62         if ( l == 0 ) {
63             syslog( LOG_ERR, "zonecheck: %.*s not in zone list", czt->zt_len,
64                     czt->zt_name );
65             return( -1 );       /* configured zone not found in net zones */
66         }
67     }
68
69     for ( ztcnt = 0, l = rtmp->rt_zt; l; l = l->l_next, ztcnt++ )
70         ;
71
72     if ( cztcnt != ztcnt ) {
73         syslog( LOG_ERR, "zonecheck: %d configured zones, %d zones found",
74                 cztcnt, ztcnt );
75         return( -1 );           /* more net zones than configured zones */
76     }
77
78     return( 0 );
79 }
80
81
82 int zip_packet( ap, from, data, len )
83     struct atport       *ap;
84     struct sockaddr_at  *from;
85     char                *data;
86     int                 len;
87 {
88     struct ziphdr       zh;
89     struct atphdr       ah;
90     struct interface    *iface;
91     struct gate         *gate;
92     struct rtmptab      *rtmp;
93     struct list         *l;
94     struct ziptab       *zt;
95     u_short             firstnet, lastnet, index, nz;
96     char                *end, zname[ 32 ], packet[ ATP_BUFSIZ ], *nzones, *lastflag;
97     char                *reply, *rend, *ziphdr;
98     int                 zlen, n, zipop, rcnt, qcnt, zcnt, zsz;
99     extern int          debug, stabletimer;
100
101     end = data + len;
102
103     if ( data >= end ) {
104         syslog( LOG_INFO, "zip_packet malformed packet" );
105         return 1;
106     }
107
108     /* get interface */
109     iface = ap->ap_iface;
110
111     switch( *data++ ) {
112     case DDPTYPE_ZIP :
113         if ( data + sizeof( struct ziphdr ) > end ) {
114             syslog( LOG_INFO, "zip_packet malformed packet" );
115             return 1;
116         }
117         memcpy( &zh, data, sizeof( struct ziphdr ));
118         data += sizeof( struct ziphdr );
119
120         switch ( zh.zh_op ) {
121         case ZIPOP_QUERY :
122             /* set up reply */
123             reply = packet;
124             rend = packet + sizeof( packet );
125             *reply++ = DDPTYPE_ZIP;
126             ziphdr = reply;
127             reply += 2;
128             rcnt = 0;
129
130             qcnt = zh.zh_count;
131
132             while ( data + sizeof( u_short ) <= end && qcnt-- > 0 ) {
133                 memcpy( &firstnet, data, sizeof( u_short ));
134                 data += sizeof( u_short );
135
136                 /*
137                  * Look for the given network number (firstnet).
138                  * Perhaps we could do better than brute force?
139                  */
140                 for ( iface = interfaces; iface; iface = iface->i_next ) {
141                     for ( rtmp = iface->i_rt; rtmp; rtmp = rtmp->rt_inext ) {
142                         if ( firstnet == rtmp->rt_firstnet ) {
143                             break;
144                         }
145                     }
146                     if ( rtmp ) {
147                         break;
148                     }
149                 }
150                 if ( rtmp == 0 ) {
151                     continue;
152                 }
153
154                 /*
155                  * Count the number of zones in this list, and the
156                  * number of byte it will consume in a reply.
157                  */
158                 for ( zsz = 0, zcnt = 0, l = rtmp->rt_zt; l; l = l->l_next ) {
159                     zcnt++;
160                     zt = (struct ziptab *)l->l_data;
161                     zsz += sizeof( u_short ) + 1 + zt->zt_len;
162                 }
163
164                 /*
165                  * We might send this list in the current reply, as the
166                  * first thing in the next reply, or as an extended packet.
167                  */
168                 if ( reply + zsz > rend ) {
169                     if ( rcnt > 0 ) {
170                         zh.zh_op = ZIPOP_REPLY;
171                         zh.zh_cnt = rcnt;
172                         memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
173                         if ( sendto( ap->ap_fd, packet, reply - packet, 0,
174                                 (struct sockaddr *)from,
175                                 sizeof( struct sockaddr_at )) < 0 ) {
176                             syslog( LOG_ERR, "zip reply sendto: %m" );
177                         }
178
179                         reply = packet + 3;
180                         rcnt = 0;
181                     }
182
183                     if ( reply + zsz > rend ) {
184                         /* ereply */
185                         for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
186                             zt = (struct ziptab *)l->l_data;
187                             if ( reply + sizeof( u_short ) + 1 + zt->zt_len >
188                                     rend ) {
189                                 zh.zh_op = ZIPOP_EREPLY;
190                                 zh.zh_cnt = zcnt;
191                                 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
192                                 if ( sendto( ap->ap_fd, packet, reply - packet,
193                                         0, (struct sockaddr *)from,
194                                         sizeof( struct sockaddr_at )) < 0 ) {
195                                     syslog( LOG_ERR, "zip reply sendto: %m" );
196                                 }
197
198                                 reply = packet + 3;
199                                 rcnt = 0;
200                             }
201
202                             memcpy( reply, &firstnet, sizeof( u_short ));
203                             reply += sizeof( u_short );
204                             *reply++ = zt->zt_len;
205                             memcpy( reply, zt->zt_name, zt->zt_len );
206                             reply += zt->zt_len;
207                         }
208
209                         if ( rcnt > 0 ) {
210                             zh.zh_op = ZIPOP_EREPLY;
211                             zh.zh_cnt = zcnt;
212                             memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
213                             if ( sendto( ap->ap_fd, packet, reply - packet, 0,
214                                     (struct sockaddr *)from,
215                                     sizeof( struct sockaddr_at )) < 0 ) {
216                                 syslog( LOG_ERR, "zip reply sendto: %m" );
217                             }
218
219                             reply = packet + 3;
220                             rcnt = 0;
221                         }
222                         continue;
223                     }
224                 }
225
226                 for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
227                     zt = (struct ziptab *)l->l_data;
228                     memcpy( reply, &firstnet, sizeof( u_short ));
229                     reply += sizeof( u_short );
230                     *reply++ = zt->zt_len;
231                     memcpy( reply, zt->zt_name, zt->zt_len );
232                     reply += zt->zt_len;
233                 }
234             }
235
236             if ( rcnt > 0 ) {
237                 zh.zh_op = ZIPOP_REPLY;
238                 zh.zh_cnt = rcnt;
239                 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
240                 if ( sendto( ap->ap_fd, packet, reply - packet, 0,
241                         (struct sockaddr *)from,
242                         sizeof( struct sockaddr_at )) < 0 ) {
243                     syslog( LOG_ERR, "zip reply sendto: %m" );
244                 }
245             }
246             break;
247
248         case ZIPOP_REPLY :
249             for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
250                 if (( from->sat_addr.s_net == 0 ||
251                         gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
252                         gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
253                     break;
254                 }
255             }
256             if ( gate == NULL ) {
257                 syslog( LOG_INFO, "zip reply from non-gateway %u.%u", 
258                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
259                 return 1;
260             }
261
262             rtmp = NULL;
263
264             do {
265                 if ( data + sizeof( u_short ) + 1 > end ) {     /* + strlen */
266                     syslog( LOG_INFO, "zip reply short (%d)", len );
267                     return 1;
268                 }
269                 memcpy( &firstnet, data, sizeof( u_short ));
270                 data += sizeof( u_short );
271
272                 if ( rtmp && rtmp->rt_firstnet != firstnet ) {
273                     /* XXX */
274                     if ( rtmp->rt_gate == NULL &&
275                             zonecheck( rtmp, gate->g_iface ) != 0 ) {
276                         syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
277                         return -1;
278                     }
279                     rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
280                 }
281
282                 /* Check if this is the interface's route. */
283                 if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
284                     rtmp = gate->g_iface->i_rt;
285                 } else {
286                     for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
287                         if ( rtmp->rt_firstnet == firstnet ) {
288                             break;
289                         }
290                     }
291
292                     /*
293                      * Update head to this rtmp entry.
294                      */
295                     if ( rtmp != 0 && gate->g_rt != rtmp ) {
296                         gate->g_rt->rt_prev->rt_next = gate->g_rt;
297                         gate->g_rt = rtmp;
298                         rtmp->rt_prev->rt_next = 0;
299                     }
300                 }
301
302                 zlen = *data++;
303                 if ( zlen > 32 || zlen <= 0 ) {
304                     syslog( LOG_INFO, "zip reply bad packet" );
305                     return 1;
306                 }
307                 if ( data + zlen > end ) {
308                     syslog( LOG_INFO, "zip reply short (%d)", len );
309                     return 1;
310                 }
311                 memcpy( zname, data, zlen );
312                 data += zlen;
313
314                 /*
315                  * We won't find any rtmp entry if the gateway is no longer
316                  * telling us about the entry.
317                  */
318                 if ( rtmp == 0 ) {
319                     syslog( LOG_INFO, "zip skip reply %u from %u.%u (no rtmp)",
320                             ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
321                             from->sat_addr.s_node );
322                 /*
323                  * Check if the route is still in use (the iprev check is
324                  * no good if rtmp is the interface's route).
325                  */
326                 } else if ( rtmp->rt_iprev == NULL && rtmp->rt_prev != NULL ) {
327                     syslog( LOG_INFO,
328                             "zip skip reply %u-%u from %u.%u (rtmp not in use)",
329                             ntohs( rtmp->rt_firstnet ),
330                             ntohs( rtmp->rt_lastnet ),
331                             ntohs( from->sat_addr.s_net ),
332                             from->sat_addr.s_node );
333                 /*
334                  * Check if we've got an outstanding query for this route.
335                  * We will often get this, since we ask every router on a
336                  * net to verify our interface's zone(s).
337                  */
338                 } else if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
339                     syslog( LOG_INFO,
340                             "zip skip reply %u-%u from %u.%u (no query)",
341                             ntohs( rtmp->rt_firstnet ),
342                             ntohs( rtmp->rt_lastnet ),
343                             ntohs( from->sat_addr.s_net ),
344                             from->sat_addr.s_node );
345                 } else {
346                     if (addzone( rtmp, zlen, zname ) < 0) {
347                         syslog(LOG_ERR, "zip_packet: addzone");
348                         return -1;
349                     }
350                     rtmp->rt_flags |= RTMPTAB_HASZONES;
351                 }
352             } while ( data < end );
353
354             if ( rtmp && rtmp->rt_flags & RTMPTAB_HASZONES ) {
355                 /* XXX */
356                 if ( rtmp->rt_gate == 0 &&
357                         zonecheck( rtmp, gate->g_iface ) != 0 ) {
358                     syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
359                     return -1;
360                 }
361                 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
362             }
363             break;
364
365         case ZIPOP_EREPLY :
366             for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
367                 if (( from->sat_addr.s_net == 0 ||
368                         gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
369                         gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
370                     break;
371                 }
372             }
373             if ( gate == NULL ) {
374                 syslog( LOG_INFO, "zip ereply from non-gateway %u.%u", 
375                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
376                 return 1;
377             }
378
379             /*
380              * Note that we're not advancing "data" here.  We do that
381              * at the top of the do-while loop, below.
382              */
383             if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
384                 syslog( LOG_INFO, "zip ereply short (%d)", len );
385                 return 1;
386             }
387             memcpy( &firstnet, data, sizeof( u_short ));
388
389             /* Check if this is the interface's route. */
390             if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
391                 rtmp = gate->g_iface->i_rt;
392             } else {
393                 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
394                     if ( rtmp->rt_firstnet == firstnet ) {
395                         break;
396                     }
397                 }
398                 if ( rtmp == NULL ) {
399                     syslog( LOG_INFO, "zip ereply %u from %u.%u (no rtmp)",
400                             ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
401                             from->sat_addr.s_node );
402                     return 1;
403                 }
404                 if ( rtmp->rt_iprev == 0 ) {
405                     syslog( LOG_INFO,
406                             "zip ereply %u-%u from %u.%u (rtmp not in use)",
407                             ntohs( rtmp->rt_firstnet ),
408                             ntohs( rtmp->rt_lastnet ),
409                             ntohs( from->sat_addr.s_net ),
410                             from->sat_addr.s_node );
411                 }
412
413                 /* update head to *next* rtmp entry */
414                 if ( rtmp->rt_next != 0 ) {
415                     gate->g_rt->rt_prev->rt_next = gate->g_rt;
416                     gate->g_rt = rtmp->rt_next;
417                     rtmp->rt_next = 0;
418                 }
419             }
420
421             if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
422                 syslog( LOG_INFO, "zip ereply %u-%u from %u.%u (no query)",
423                         ntohs( rtmp->rt_firstnet ),
424                         ntohs( rtmp->rt_lastnet ),
425                         ntohs( from->sat_addr.s_net ),
426                         from->sat_addr.s_node );
427                 return 0;
428             }
429
430             do {
431                 /*
432                  * We copy out firstnet, twice (see above).  Not
433                  * a big deal, and it makes the end condition cleaner.
434                  */
435                 if ( data + sizeof( u_short ) + 1 > end ) {     /* + strlen */
436                     syslog( LOG_INFO, "zip ereply short (%d)", len );
437                     return 1;
438                 }
439                 memcpy( &firstnet, data, sizeof( u_short ));
440                 data += sizeof( u_short );
441
442                 /* check route */
443                 if ( firstnet != rtmp->rt_firstnet ) {
444                     syslog( LOG_INFO, "zip ereply with multiple nets" );
445                     return 1;
446                 }
447
448                 zlen = *data++;
449                 if ( zlen > 32 || zlen <= 0 ) {
450                     syslog( LOG_INFO, "zip ereply bad zone length (%d)", zlen );
451                     return 1;
452                 }
453                 if ( data + zlen > end ) {
454                     syslog( LOG_INFO, "zip ereply short (%d)", len );
455                     return 1;
456                 }
457                 memcpy( zname, data, zlen );
458                 data += zlen;
459                 if (addzone( rtmp, zlen, zname ) < 0) {
460                     syslog(LOG_ERR, "zip_packet: addzone");
461                     return -1;
462                 }
463             } while ( data < end );
464
465             if ( rtmp ) {
466                 /*
467                  * Count zones for rtmptab entry.
468                  */
469                 for ( n = 0, l = rtmp->rt_zt; l; l = l->l_next, n++ )
470                     ;
471                 if ( n == zh.zh_count ) {
472                     rtmp->rt_flags |= RTMPTAB_HASZONES;
473                     /* XXX */
474                     if ( rtmp->rt_gate == 0 &&
475                             zonecheck( rtmp, gate->g_iface ) != 0 ) {
476                         syslog( LOG_ERR, "zip_packet seed zonelist mismatch" );
477                         return -1;
478                     }
479                     rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
480                 }
481             }
482             break;
483
484         case ZIPOP_GNI :
485             /*
486              * Don't answer with bogus information.
487              */
488             if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
489                 iface->i_rt->rt_zt == 0 ||
490                 ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
491                 return 0;
492             }
493
494             if ( zh.zh_zero != 0 || data + 2 * sizeof( u_short ) > end ) {
495                 syslog( LOG_INFO, "zip_packet malformed packet" );
496                 return 1;
497             }
498
499             memcpy( &firstnet, data, sizeof( u_short ));
500             data += sizeof( u_short );
501             memcpy( &lastnet, data, sizeof( u_short ));
502             data += sizeof( u_short );
503             if ( firstnet != 0 || lastnet != 0 || data >= end ) {
504                 syslog( LOG_INFO, "zip_packet malformed packet" );
505                 return 1;
506             }
507
508             zlen = *data++;
509             if ( zlen < 0 || zlen > 32 ) {
510                 syslog( LOG_INFO, "zip_packet malformed packet" );
511                 return 1;
512             }
513             memcpy( zname, data, zlen );
514
515             data = packet;
516             end = data + sizeof( packet );
517             zh.zh_op = ZIPOP_GNIREPLY;
518             zh.zh_flags = 0;
519
520             /*
521              * Skip to the nets.  Fill in header when we're done.
522              */
523             data += 1 + sizeof( struct ziphdr );
524             memcpy( data, &iface->i_rt->rt_firstnet, sizeof( u_short ));
525             data += sizeof( u_short );
526             memcpy( data, &iface->i_rt->rt_lastnet, sizeof( u_short ));
527             data += sizeof( u_short );
528
529             *data++ = zlen;
530             memcpy( data, zname, zlen );
531             data += zlen;
532
533             /*
534              * Check if the given zone is valid.  If it's valid, just fill in
535              * the multicast address.  If it's not, fill the multicast address
536              * in with the default zone and return the default zone.
537              */
538             for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
539                 zt = (struct ziptab *)l->l_data;
540                 if ( zt->zt_len == zlen &&
541                         strndiacasecmp( zname, zt->zt_name, zlen ) == 0 ) {
542                     break;
543                 }
544             }
545             if ( l == 0 ) {
546                 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
547                 zh.zh_flags |= ZIPGNI_INVALID;
548             }
549
550             for ( n = 0, l = iface->i_rt->rt_zt; l; l = l->l_next, n++ )
551                 ;
552             if ( n == 1 ) {
553                 zh.zh_flags |= ZIPGNI_ONEZONE;
554             }
555
556             /* multicast */
557             *data++ = 6;        /* sizeof ??? */
558             if (zone_bcast(zt) < 0) {
559               syslog(LOG_ERR, "zip_packet: zone_bcast");
560               return -1;
561             }
562             memcpy(data, zt->zt_bcast, 6);
563             data += 6;
564
565             /*
566              * Add default zone.
567              */
568             if ( zh.zh_flags & ZIPGNI_INVALID ) {
569                 *data++ = zt->zt_len;
570                 memcpy( data, zt->zt_name, zt->zt_len );
571                 data += zt->zt_len;
572             }
573
574             /* fill in header */
575             *packet = DDPTYPE_ZIP;
576             memcpy( packet + 1, &zh, sizeof( struct ziphdr ));
577
578             /*
579              * If the address we received this request from isn't correct
580              * for the net we received it on, send a broadcast.
581              */
582             if ( ntohs( from->sat_addr.s_net ) <
583                     ntohs( iface->i_rt->rt_firstnet ) ||
584                     ntohs( from->sat_addr.s_net ) >
585                     ntohs( iface->i_rt->rt_lastnet )) {
586                 from->sat_addr.s_net = 0;
587                 from->sat_addr.s_node = ATADDR_BCAST;
588             }
589
590             if ( sendto( ap->ap_fd, packet, data - packet, 0,
591                     (struct sockaddr *)from,
592                     sizeof( struct sockaddr_at )) < 0 ) {
593                 syslog( LOG_ERR, "zip gni sendto %u.%u: %m",
594                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
595                 return 1;
596             }
597             break;
598
599         case ZIPOP_GNIREPLY :
600             /*
601              * Ignore ZIP GNIReplys which are either late or unsolicited.
602              */
603             syslog( LOG_DEBUG, "zip gnireply from %u.%u (%s %x)",
604                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
605                     iface->i_name, iface->i_flags );
606
607             if (( iface->i_flags & ( IFACE_CONFIG|IFACE_PHASE1 )) ||
608                     ( iface->i_flags & IFACE_ADDR ) == 0 ) {
609                 syslog( LOG_DEBUG, "zip ignoring gnireply" );
610                 return 1;
611             }
612
613             if ( data + 2 * sizeof( u_short ) > end ) {
614                 syslog( LOG_INFO, "zip_packet malformed packet" );
615                 return 1;
616             }
617             memcpy( &firstnet, data, sizeof( u_short ));
618             data += sizeof( u_short );
619             memcpy( &lastnet, data, sizeof( u_short ));
620             data += sizeof( u_short );
621
622             /*
623              * We never ask for a zone, so we can get back what the
624              * default zone is.
625              */
626             if ( data >= end || data + *data > end ) {
627                 syslog( LOG_INFO, "zip_packet malformed packet" );
628                 return 1;
629             }
630             if ( *data++ != 0 ) {
631                 syslog( LOG_INFO, "zip_packet unsolicited zone" );
632                 return 1;
633             }
634
635             /* skip multicast (should really check it) */
636             if ( data >= end || data + *data > end ) {
637                 syslog( LOG_INFO, "zip_packet malformed packet" );
638                 return 1;
639             }
640             data += *data + 1;
641
642             if ( data >= end || data + *data > end ) {
643                 syslog( LOG_INFO, "zip_packet malformed packet" );
644                 return 1;
645             }
646
647             /*
648              * First, if we're not seed, we always get our zone information
649              * from the net -- we don't even save what was in the file.
650              * Second, if we are seed, we keep our zone list in the
651              * interface structure, not in the zone table.  This allows us
652              * to check that the net is giving us good zones.
653              */
654             if ( iface->i_flags & IFACE_SEED ) {
655                 if ( iface->i_czt->zt_len != *data ||
656                         strndiacasecmp( iface->i_czt->zt_name,
657                         data + 1, *data ) != 0 ) {
658                     syslog( LOG_ERR, "default zone mismatch on %s",
659                             iface->i_name );
660                     syslog( LOG_ERR, "%.*s != %.*s",
661                             iface->i_czt->zt_len, iface->i_czt->zt_name,
662                             *data, data + 1 );
663                     syslog( LOG_ERR, "Seed error! Exiting!" );
664                     return -1;
665                 }
666             }
667
668             if (addzone( iface->i_rt, *data, data + 1 ) < 0) {
669                 syslog(LOG_ERR, "zip_packet: addzone");
670                 return -1;
671             }
672             
673             /*
674              * The netrange we received from the router doesn't match the
675              * range we have locally. This is not a problem, unless we
676              * have seed information.
677              */
678             if ( firstnet != iface->i_rt->rt_firstnet ||
679                     lastnet != iface->i_rt->rt_lastnet ) {
680                 if ( iface->i_flags & IFACE_SEED ) {
681                     syslog( LOG_ERR, "netrange mismatch on %s",
682                             iface->i_name );
683                     syslog( LOG_ERR, "%u-%u != %u-%u",
684                             ntohs( firstnet ), ntohs( lastnet ),
685                             ntohs( iface->i_rt->rt_firstnet ),
686                             ntohs( iface->i_rt->rt_lastnet ));
687                     syslog( LOG_ERR, "Seed error! Exiting!" );
688                     return -1;
689                 }
690
691
692                 /*
693                  * It is possible that we will corrupt our route database
694                  * by just forcing this change.  A better solution would
695                  * be to search all of our current routes, looking for
696                  * this new route, and delete any old versions.  Also, we
697                  * would call rtmp_delete() on the old net range, in case
698                  * there is some other net which actually had that range.  XXX
699                  */
700                 iface->i_rt->rt_firstnet = firstnet;
701                 iface->i_rt->rt_lastnet = lastnet;
702
703                 if ( ntohs( iface->i_addr.sat_addr.s_net ) <
704                         ntohs( firstnet ) ||
705                         ntohs( iface->i_addr.sat_addr.s_net ) >
706                         ntohs( lastnet )) {
707                     iface->i_addr.sat_addr.s_net = 0;   /* ATADDR_ANYNET? */
708                 }
709                 setaddr( iface, IFACE_PHASE2, iface->i_addr.sat_addr.s_net,
710                         iface->i_addr.sat_addr.s_node, firstnet, lastnet );
711                 stabletimer = UNSTABLE;
712             }
713
714             /* add addr to loopback route */
715             if ( looproute( iface, RTMP_ADD )) { /* -1 or 1 */
716                 syslog( LOG_ERR,
717                         "zip_packet: can't route %u.%u to loopback: %m",
718                         ntohs( iface->i_addr.sat_addr.s_net ),
719                         iface->i_addr.sat_addr.s_node );
720                 return -1;
721             }
722
723             syslog( LOG_INFO, "zip_packet configured %s from %u.%u",
724                     iface->i_name, ntohs( from->sat_addr.s_net ),
725                     from->sat_addr.s_node );
726             iface->i_flags |= IFACE_CONFIG;
727             if ( iface == ciface ) {
728                 ciface = ciface->i_next;
729                 bootaddr( ciface );
730             }
731             break;
732
733         case ZIPOP_NOTIFY :
734 #ifdef DEBUG
735             printf( "zip notify from %u.%u\n", ntohs( from->sat_addr.s_net ),
736                     from->sat_addr.s_node );
737 #endif DEBUG
738             break;
739
740         default :
741             syslog( LOG_INFO, "zip_packet bad zip op from %u.%u\n",
742                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
743         }
744         break;
745
746     case DDPTYPE_ATP :
747         if ( data + sizeof( struct atphdr ) > end ) {
748             syslog( LOG_INFO, "zip atp malformed packet" );
749             return 1;
750         }
751         memcpy( &ah, data, sizeof( struct atphdr ));
752         data += sizeof( struct atphdr );
753         if ( ah.atphd_ctrlinfo != ATP_TREQ ) {
754             syslog( LOG_INFO, "zip atp bad control" );
755             return 1;
756         }
757         ah.atphd_ctrlinfo = ATP_TRESP | ATP_EOM;
758         if ( ah.atphd_bitmap != 1 ) {
759             syslog( LOG_ERR, "zip atp bad bitmap" );
760             return 1;
761         }
762         ah.atphd_bitmap = 0;
763
764         zipop = *data++;
765         data++;
766         memcpy( &index, data, sizeof( u_short ));
767         data += sizeof( u_short );
768         index = ntohs( index );
769         if ( data != end ) {
770             syslog( LOG_INFO, "zip atp malformed packet" );
771             return 1;
772         }
773
774         data = packet;
775         end = data + sizeof( packet );
776         *data++ = DDPTYPE_ATP;
777         memcpy( data, &ah, sizeof( struct atphdr ));
778         data += sizeof( struct atphdr );
779         lastflag = data++;              /* mark and space for last flag */
780         *data++ = 0;
781         nzones = data;                  /* mark and space for zone count */
782         data += sizeof( u_short );
783
784         switch ( zipop ) {
785         case ZIPOP_GETMYZONE :
786             if ( index != 0 ) {
787                 syslog( LOG_INFO, "zip atp gmz bad index" );
788                 return 1;
789             }
790
791             if ( iface->i_flags & IFACE_LOOPBACK ) {
792                 iface = interfaces->i_next;     /* first interface */
793             } else if ( ntohs( iface->i_rt->rt_firstnet ) >
794                     ntohs( from->sat_addr.s_net ) ||
795                     ntohs( iface->i_rt->rt_lastnet ) <
796                     ntohs( from->sat_addr.s_net )) {
797                 return 0;
798             }
799
800             if ( iface->i_rt->rt_zt == 0 ) {
801                 return 0;
802             }
803             zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
804             if ( data + 1 + zt->zt_len > end ) {
805                 syslog( LOG_INFO, "zip atp gmz reply too long" );
806                 return 1;
807             }
808             *data++ = zt->zt_len;
809             memcpy( data, zt->zt_name, zt->zt_len );
810             data += zt->zt_len;
811
812             *lastflag = 0;
813             nz = 1;
814             break;
815
816         case ZIPOP_GETZONELIST :
817             for ( zt = ziptab; zt && ( index > 1 ); zt = zt->zt_next, index-- )
818                 ;
819             for ( nz = 0; zt; zt = zt->zt_next, nz++ ) {
820                 if ( data + 1 + zt->zt_len > end ) {
821                     break;
822                 }
823                 *data++ = zt->zt_len;
824                 memcpy( data, zt->zt_name, zt->zt_len );
825                 data += zt->zt_len;
826             }
827
828             *lastflag = ( zt == 0 );            /* Too clever? */
829             break;
830
831         case ZIPOP_GETLOCALZONES :
832             if ( iface->i_flags & IFACE_LOOPBACK ) {
833                 iface = interfaces->i_next;     /* first interface */
834             } else if ( ntohs( iface->i_rt->rt_firstnet ) >
835                     ntohs( from->sat_addr.s_net ) ||
836                     ntohs( iface->i_rt->rt_lastnet ) <
837                     ntohs( from->sat_addr.s_net )) {
838                 return 0;
839             }
840
841             for ( l = iface->i_rt->rt_zt; l && ( index > 1 );
842                     l = l->l_next, index-- )
843                 ;
844             for ( nz = 0; l; l = l->l_next, nz++ ) {
845                 zt = (struct ziptab *)l->l_data;
846                 if ( data + 1 + zt->zt_len > end ) {
847                     break;
848                 }
849                 *data++ = zt->zt_len;
850                 memcpy( data, zt->zt_name, zt->zt_len );
851                 data += zt->zt_len;
852             }
853
854             *lastflag = ( l == 0 );
855             break;
856
857         default :
858             syslog( LOG_INFO, "zip atp bad option" );
859             return 1;
860         }
861
862         /* send reply */
863         if ( nz > 0 ) {
864             nz = htons( nz );
865             memcpy( nzones, &nz, sizeof( u_short ));
866             if ( sendto( ap->ap_fd, packet, data - packet, 0,
867                     (struct sockaddr *)from,
868                     sizeof( struct sockaddr_at )) < 0 ) {
869                 syslog( LOG_ERR, "zip atp sendto %u.%u: %m",
870                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
871                 return 1;
872             }
873         }
874         break;
875
876     default :
877         syslog( LOG_INFO, "zip_packet bad ddp type from %u.%u\n",
878                 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
879         return 1;
880     }
881
882     return 0;
883 }
884
885 int zip_getnetinfo( iface )
886     struct interface    *iface;
887 {
888     struct atport       *ap;
889     struct ziphdr       zh;
890     struct sockaddr_at  sat;
891     char                *data, packet[ 40 ];
892     u_short             net;
893
894     syslog( LOG_INFO, "zip_getnetinfo for %s", iface->i_name );
895
896     for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
897         if ( ap->ap_packet == zip_packet ) {
898             break;
899         }
900     }
901     if ( ap == 0 ) {
902         syslog( LOG_ERR, "zip_getnetinfo can't find zip socket!" );
903         return -1;
904     }
905
906     data = packet;
907
908     *data++ = DDPTYPE_ZIP;
909
910     zh.zh_op = ZIPOP_GNI;
911     zh.zh_zero = 0;
912     memcpy( data, &zh, sizeof( struct ziphdr ));
913     data += sizeof( struct ziphdr );
914     net = 0;
915     memcpy( data, &net, sizeof( u_short ));
916     data += sizeof( u_short );
917     memcpy( data, &net, sizeof( u_short ));
918     data += sizeof( u_short );
919
920     /*
921      * Set our requesting zone to NULL, so the response will contain
922      * the default zone.
923      */
924     *data++ = 0;
925
926 #ifdef BSD4_4
927     sat.sat_len = sizeof( struct sockaddr_at );
928 #endif BSD4_4
929     sat.sat_family = AF_APPLETALK;
930     sat.sat_addr.s_net = 0;
931     sat.sat_addr.s_node = ATADDR_BCAST;
932     sat.sat_port = ap->ap_port;
933
934     if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat,
935             sizeof( struct sockaddr_at )) < 0 ) {
936         syslog( LOG_ERR, "zip_getnetinfo sendto: %m" );
937         return -1;
938     }
939     return 0;
940 }
941
942     struct ziptab *
943 newzt( len, name )
944     const int           len;
945     const char  *name;
946 {
947     struct ziptab       *zt;
948
949     if (( zt = (struct ziptab *)calloc(1, sizeof( struct ziptab ))) == NULL ) {
950         return( NULL );
951     }
952
953     zt->zt_len = len;
954     if (( zt->zt_name = (char *)malloc( len )) == NULL ) {
955         free(zt);
956         return( NULL );
957     }
958
959     memcpy( zt->zt_name, name, len );
960     return( zt );
961 }
962
963
964 /*
965  * Insert at the end.  Return 1 if a mapping already exists, 0 otherwise.
966  * -1 on error.
967  */
968 static int add_list( head, data )
969     struct list **head;
970     void        *data;
971 {
972     struct list *l, *l2;
973
974     for ( l = *head; l; l = l->l_next ) {
975         if ( l->l_data == data ) {
976             return( 1 );
977         }
978     }
979     if (( l = (struct list *)malloc( sizeof( struct list ))) == NULL ) {
980         syslog( LOG_ERR, "add_list malloc: %m" );
981         return -1;
982     }
983
984     l->l_data = data;
985     l->l_next = NULL;
986     if ( *head == NULL ) {
987         l->l_prev = NULL;
988         *head = l;
989     } else {
990         /* find end of list */
991         for ( l2 = *head; l2->l_next; l2 = l2->l_next )
992             ;
993         l->l_prev = l2;
994         l2->l_next = l;
995     }
996     return( 0 );
997 }
998
999 int addzone( rt, len, zone )
1000     struct rtmptab      *rt;
1001     int                 len;
1002     char                *zone;
1003 {
1004     struct ziptab       *zt;
1005     int                 cc, exists = 0;
1006
1007     for ( zt = ziptab; zt; zt = zt->zt_next ) {
1008         if ( zt->zt_len == len &&
1009                 strndiacasecmp( zt->zt_name, zone, len ) == 0 ) {
1010             break;
1011         }
1012     }
1013     if ( zt == NULL ) {
1014         if (( zt = newzt( len, zone )) == NULL ) {
1015             syslog( LOG_ERR, "addzone newzt: %m" );
1016             return -1;
1017         }
1018         if ( ziptab == NULL ) {
1019             zt->zt_prev = NULL;
1020             ziptab = zt;
1021         } else {
1022             zt->zt_prev = ziplast;
1023             ziplast->zt_next = zt;
1024         }
1025         ziplast = zt;
1026     }
1027
1028     if ((cc = add_list( &zt->zt_rt, rt )) < 0) 
1029       return -1;
1030
1031     if (cc)
1032       exists++;
1033
1034     if ((cc = add_list( &rt->rt_zt, zt )) < 0 )
1035       return -1;
1036
1037     if (cc) {
1038         if ( !exists ) {
1039             syslog( LOG_ERR, "addzone corrupted route/zone mapping" );
1040             return -1;
1041         }
1042         /*
1043          * We get the repeat for local nets which have zone information
1044          * already: we ask anyway, just to make sure.
1045          */
1046         
1047         return 0;
1048     }
1049     if ( exists ) {
1050         syslog( LOG_ERR, "addzone corrupted zone/route mapping" );
1051         return -1;
1052     }
1053 }