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