]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/nbp.c
Initial revision
[netatalk.git] / etc / atalkd / nbp.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved. See COPYRIGHT.
4  */
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/syslog.h>
9 #include <sys/types.h>
10 #include <sys/param.h>
11 #include <sys/socket.h>
12 #include <sys/ioctl.h>
13 #include <net/if.h>
14 #include <netatalk/at.h>
15 #include <atalk/ddp.h>
16 #include <atalk/atp.h>
17 #include <atalk/nbp.h>
18 #include <atalk/util.h>
19
20 #ifdef __svr4__
21 #include <sys/sockio.h>
22 #endif __svr4__
23
24 #include "atserv.h"
25 #include "interface.h"
26 #include "list.h"
27 #include "rtmp.h"
28 #include "gate.h"
29 #include "zip.h"
30 #include "nbp.h"
31 #include "multicast.h"
32
33 extern int      transition;
34
35 struct nbptab   *nbptab = NULL;
36
37 static 
38 void nbp_ack( fd, nh_op, nh_id, to )
39     int                 fd;
40     int                 nh_op;
41     int                 nh_id;
42     struct sockaddr_at  *to;
43 {
44     struct nbphdr       nh;
45     char                *data, packet[ SZ_NBPHDR + 1 ];
46
47     nh.nh_op = nh_op;
48     nh.nh_cnt = 0;
49     nh.nh_id = nh_id;
50     data = packet;
51     *data++ = DDPTYPE_NBP;
52     bcopy( &nh, data, SZ_NBPHDR );
53     data += SZ_NBPHDR;
54     if ( sendto( fd, packet, data - packet, 0, (struct sockaddr *)to,
55             sizeof( struct sockaddr_at )) < 0 ) {
56         syslog( LOG_ERR, "sendto: %m" );
57     }
58 }
59
60 int nbp_packet( ap, from, data, len )
61     struct atport       *ap;
62     struct sockaddr_at  *from;
63     char                *data;
64     int                 len;
65 {
66     struct nbphdr       nh;
67     struct nbptuple     nt;
68     struct nbpnve       nn;
69     struct sockaddr_at  sat;
70     struct nbptab       *ntab;
71     struct ziptab       *zt;
72     struct interface    *iface;
73     struct list         *l;
74     struct rtmptab      *rtmp;
75     char                *end, *nbpop, *zonep, packet[ ATP_BUFSIZ ];
76     int                 n, i, cc, locallkup;
77
78     end = data + len;
79     if ( data >= end ) {
80         syslog( LOG_INFO, "nbp_packet malformed packet" );
81         return 1;
82     }
83     if ( *data++ != DDPTYPE_NBP ) {
84         syslog( LOG_INFO, "nbp_packet bad ddp type" );
85         return 1;
86     }
87
88     if ( data + SZ_NBPHDR + SZ_NBPTUPLE > end ) {
89         syslog( LOG_INFO, "nbp_packet: malformed packet" );
90         return 1;
91     }
92     memcpy( &nh, data, SZ_NBPHDR );
93     nbpop = data;                       /* remember for fwd and brrq */
94     data += SZ_NBPHDR;
95     if ( nh.nh_cnt != 1 ) {
96         syslog( LOG_INFO, "nbp_packet: bad tuple count (%d/%d)", nh.nh_cnt,
97                 nh.nh_op );
98         return 1;
99     }
100
101     memcpy( &nt, data, SZ_NBPTUPLE );
102     data += SZ_NBPTUPLE;
103
104     memset( &nn.nn_sat, 0, sizeof( struct sockaddr_at ));
105 #ifdef BSD4_4
106     nn.nn_sat.sat_len = sizeof( struct sockaddr_at );
107 #endif BSD4_4
108     nn.nn_sat.sat_family = AF_APPLETALK;
109     nn.nn_sat.sat_addr.s_net = nt.nt_net;
110     nn.nn_sat.sat_addr.s_node = nt.nt_node;
111     nn.nn_sat.sat_port = nt.nt_port;
112
113     /* object */
114     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
115         syslog( LOG_INFO, "nbp_packet: malformed packet" );
116         return 1;
117     }
118     nn.nn_objlen = *data++;
119     memcpy( nn.nn_obj, data, nn.nn_objlen );
120     data += nn.nn_objlen;
121
122     /* type */
123     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
124         syslog( LOG_INFO, "nbp_packet: malformed packet" );
125         return 1;
126     }
127     nn.nn_typelen = *data++;
128     memcpy( nn.nn_type, data, nn.nn_typelen );
129     data += nn.nn_typelen;
130
131     /* zone */
132     if ( data >= end || ( *data < 0 || *data > 32 ) || data + *data > end ) {
133         syslog( LOG_INFO, "nbp_packet: malformed packet" );
134         return 1;
135     }
136     zonep = data;                       /* remember for fwd */
137     nn.nn_zonelen = *data++;
138     memcpy( nn.nn_zone, data, nn.nn_zonelen );
139     data += nn.nn_zonelen;
140
141     if ( data != end ) {
142         syslog( LOG_INFO, "nbp_packet: malformed packet" );
143         return 1;
144     }
145
146     locallkup = 0;
147     switch ( nh.nh_op ) {
148
149     case NBPOP_RGSTR :
150         /*
151          * Find the ziptab entry for the zone we're trying to register in.
152          */
153         if ( nn.nn_zonelen == 0 ||
154                 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
155             if ( interfaces->i_next->i_rt->rt_zt ) {
156                 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
157             } else {
158                 zt = 0;
159             }
160         } else {
161             for ( zt = ziptab; zt; zt = zt->zt_next ) {
162                 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
163                         nn.nn_zone, zt->zt_len ) == 0 ) {
164                     break;
165                 }
166             }
167             if ( zt == 0 ) {
168                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
169                 return 0;
170             }
171         }
172
173         /*
174          * Observe that we don't have to do any local-zone verification
175          * if the zone aleady has a multicast address set.
176          */
177         if ( zt != 0 && zt->zt_bcast == 0 ) {
178             /*
179              * Check if zone is associated with any of our local interfaces.
180              */
181             for ( iface = interfaces; iface; iface = iface->i_next ) {
182                 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
183                     if ( zt == (struct ziptab *)l->l_data ) {
184                         break;
185                     }
186                 }
187                 if ( l != 0 ) {
188                     break;
189                 }
190             }
191             if ( iface == 0 ) {
192                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
193                 return 0;
194             }
195
196             /* calculate and save multicast address */
197             if (zone_bcast(zt) < 0) {
198                 syslog(LOG_ERR, "nbp_packet: zone_bcast");
199                 return -1;
200             }
201
202             for ( iface = interfaces; iface; iface = iface->i_next ) {
203                 if (( iface->i_flags & IFACE_PHASE2 ) == 0 ) {
204                     continue;
205                 }
206                 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
207                     if ( zt == (struct ziptab *)l->l_data ) {
208                         /* add multicast */
209                         if (addmulti(iface->i_name, zt->zt_bcast) < 0) {
210                             syslog( LOG_ERR, "nbp_packet: addmulti: %m" );
211                             return -1;
212                         }
213                     }
214                 }
215             }
216         }
217
218         if (( ntab = (struct nbptab *)malloc( sizeof( struct nbptab )))
219                 == 0 ) {
220             syslog( LOG_ERR, "nbp_packet: malloc: %m" );
221             return -1;
222         }
223         memcpy( &ntab->nt_nve, &nn, sizeof( struct nbpnve ));
224         ntab->nt_iface = ap->ap_iface;
225         ntab->nt_next = nbptab;
226         ntab->nt_prev = 0;
227         if ( nbptab ) {
228             nbptab->nt_prev = ntab;
229         }
230         nbptab = ntab;
231
232         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
233         break;
234
235     case NBPOP_UNRGSTR :
236         /* deal with local zone info */
237         if (( nn.nn_zonelen == 1 && *nn.nn_zone == '*' ) ||
238             ( nn.nn_zonelen == 0 )) {
239           locallkup = 1;
240           if ( interfaces->i_next->i_rt->rt_zt ) {
241             zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
242           } else {
243             zt = NULL;
244           }
245         }
246
247         /* remove from our data, perhaps removing a multicast address */
248         for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
249             if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
250                     strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
251                     nn.nn_objlen )) {
252                 continue;
253             }
254             if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
255                     strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
256                     nn.nn_typelen )) {
257                 continue;
258             }
259             /*
260              * I *think* we really do check the zone, here.
261              *
262              * i changed it to better handle local zone cases as well.
263              * -- asun
264              */
265             
266             /* match local zones */
267             if (locallkup) {
268               /* ntab is also local zone */
269               if (( ntab->nt_nve.nn_zonelen == 1 &&
270                     *ntab->nt_nve.nn_zone == '*' ) || 
271                   (ntab->nt_nve.nn_zonelen == 0))
272                 break;
273               
274               /* ntab is default zone */
275               if (zt && (zt->zt_len == ntab->nt_nve.nn_zonelen) &&
276                   (strndiacasecmp(ntab->nt_nve.nn_zone, zt->zt_name,
277                                   zt->zt_len) == 0)) {
278                 break;
279               }
280             }
281             
282             /* match particular zone */
283             if ((ntab->nt_nve.nn_zonelen == nn.nn_zonelen) &&
284                 (strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
285                                 nn.nn_zonelen ) == 0)) {
286                 break;
287             }
288         }
289         if ( ntab == 0 ) {
290             nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
291             return 0;
292         }
293
294         if ( ntab->nt_next != 0 ) {
295             ntab->nt_next->nt_prev = ntab->nt_prev;
296         }
297         if ( ntab->nt_prev != 0 ) {
298             ntab->nt_prev->nt_next = ntab->nt_next;
299         }
300         if ( ntab == nbptab ) {
301             nbptab = ntab->nt_next;
302         }
303
304         /*
305          * Check for another nbptab entry with the same zone.  If
306          * there isn't one, find the ziptab entry for the zone and
307          * remove the multicast address from the appropriate interfaces.
308          * XXX
309          */
310
311         nbp_ack( ap->ap_fd, NBPOP_OK, (int)nh.nh_id, from );
312         break;
313
314     case NBPOP_BRRQ :
315         /*
316          * Couple of things:  1. Unless we have the -t flag (which is sort
317          * of a misnomer, since you need it if you're doing any phase 1
318          * work), always send NBPOP_FWD.  2. If we get a zone of '*',
319          * and we know what the sender meant by '*', we copy the real
320          * zone into the packet.
321          */
322         if ( nn.nn_zonelen == 0 ||
323                 ( nn.nn_zonelen == 1 && *nn.nn_zone == '*' )) {
324             iface = ap->ap_iface;
325             if ( iface && iface->i_rt->rt_zt ) {
326                 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
327             } else if ( interfaces->i_next->i_rt->rt_zt ) {
328                 zt = (struct ziptab *)interfaces->i_next->i_rt->rt_zt->l_data;
329             } else {
330                 zt = NULL;
331             }
332
333             /*
334              * Copy zone into packet.  Note that we're changing len, data, and
335              * nbpop.  Later, we'll use ( data - len ) to mean the beginning
336              * of this packet.
337              */
338             if ( zt ) {
339                 memcpy( packet, data - len, len );
340                 nbpop = packet + ( len - ( data - nbpop ));
341                 data = packet + ( len - ( data - zonep ));
342                 *data++ = zt->zt_len;
343                 memcpy( data, zt->zt_name, zt->zt_len );
344                 data += zt->zt_len;
345                 len = data - packet;
346             }
347         } else {
348             for ( zt = ziptab; zt; zt = zt->zt_next ) {
349                 if ( zt->zt_len == nn.nn_zonelen && strndiacasecmp( zt->zt_name,
350                         nn.nn_zone, zt->zt_len ) == 0 ) {
351                     break;
352                 }
353             }
354             if ( zt == 0 ) {
355                 nbp_ack( ap->ap_fd, NBPOP_ERROR, (int)nh.nh_id, from );
356                 return 0;
357             }
358         }
359
360         /*
361          * If we've got no zones, send out LKUP on the local net.
362          * Otherwise, look through the zone table.
363          */
364         if ( zt == 0 ) {
365 #ifdef BSD4_4
366             sat.sat_len = sizeof( struct sockaddr_at );
367 #endif BSD4_4
368             sat.sat_family = AF_APPLETALK;
369             sat.sat_port = ap->ap_port;
370
371             nh.nh_op = NBPOP_LKUP;
372             memcpy( nbpop, &nh, SZ_NBPHDR );
373             sat.sat_addr.s_net = 0;                     /* XXX */
374             sat.sat_addr.s_node = ATADDR_BCAST;
375
376             /* Find the first non-loopback ap */
377             for ( iface = interfaces; iface; iface = iface->i_next ) {
378                 if ((( iface->i_flags & IFACE_LOOPBACK ) == 0) &&
379                     (iface == ap->ap_iface || 
380                     (iface->i_flags & IFACE_ISROUTER))) {
381                     break;
382                 }
383             }
384             if ( iface == 0 ) {
385                 return 0;
386             }
387             for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
388                 if ( ap->ap_packet == nbp_packet ) {
389                     break;
390                 }
391             }
392
393             if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)&sat,
394                     sizeof( struct sockaddr_at )) < 0 ) {
395                 syslog( LOG_ERR, "nbp brrq sendto: %m" );
396             }
397
398             locallkup = 1;
399         } else {
400 #ifdef BSD4_4
401             sat.sat_len = sizeof( struct sockaddr_at );
402 #endif BSD4_4
403             sat.sat_family = AF_APPLETALK;
404             sat.sat_port = ap->ap_port;
405             for ( l = zt->zt_rt; l; l = l->l_next ) {
406                 rtmp = (struct rtmptab *)l->l_data;
407
408                 if ( rtmp->rt_gate == 0 ) {
409                     for ( iface = interfaces; iface;
410                             iface = iface->i_next ) {
411                         if ( iface->i_rt == rtmp ) {
412                             break;
413                         }
414                     }
415                     if ( !iface ) {
416                         syslog( LOG_ERR, "nbp_packet: \
417 Can't find route's interface!" );
418                         return -1;
419                     }
420                     ap = iface->i_ports;
421                 } else {
422                     ap = rtmp->rt_gate->g_iface->i_ports;
423                 }
424                 for ( ; ap; ap = ap->ap_next ) {
425                     if ( ap->ap_packet == nbp_packet ) {
426                         break;
427                     }
428                 }
429                 if ( !ap ) {
430                     syslog( LOG_ERR, "nbp_packet: Can't find port!" );
431                     return -1;
432                 }
433
434                 if ( transition &&
435                         ( rtmp->rt_flags & RTMPTAB_EXTENDED ) == 0 ) {
436                     if ( rtmp->rt_gate == 0 ) {
437                         locallkup = 1;
438                     }
439                     nh.nh_op = NBPOP_LKUP;
440                     bcopy( &nh, nbpop, SZ_NBPHDR );
441                     sat.sat_addr.s_net = rtmp->rt_firstnet;
442                     sat.sat_addr.s_node = ATADDR_BCAST;
443                 } else {
444                     if ( rtmp->rt_gate == 0 ) {
445                         nh.nh_op = NBPOP_LKUP;
446                         bcopy( &nh, nbpop, SZ_NBPHDR );
447                         sat.sat_addr.s_net = 0;
448                         sat.sat_addr.s_node = ATADDR_BCAST;
449                         locallkup = 1;
450                     } else {
451                         nh.nh_op = NBPOP_FWD;
452                         bcopy( &nh, nbpop, SZ_NBPHDR );
453                         sat.sat_addr.s_net = rtmp->rt_firstnet;
454                         sat.sat_addr.s_node = 0;
455                     }
456                 }
457
458                 if ( sendto( ap->ap_fd, data - len, len, 0,
459                         (struct sockaddr *)&sat,
460                         sizeof( struct sockaddr_at )) < 0 ) {
461                     syslog( LOG_ERR, "nbp brrq sendto %u.%u: %m",
462                             ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
463                     continue;
464                 }
465             }
466         }
467
468         if ( !locallkup ) {
469             break;
470         }
471         /*FALL THROUGH*/
472
473     case NBPOP_FWD :
474         /* send lkup on net. we need to make sure we're a router. */
475         if ( !locallkup && (ap->ap_iface->i_flags & IFACE_ISROUTER)) {
476             nh.nh_op = NBPOP_LKUP;
477             bcopy( &nh, nbpop, SZ_NBPHDR );
478             from->sat_addr.s_net = 0;
479             from->sat_addr.s_node = ATADDR_BCAST;
480             if ( sendto( ap->ap_fd, data - len, len, 0, (struct sockaddr *)from,
481                     sizeof( struct sockaddr_at )) < 0 ) {
482                 syslog( LOG_ERR, "nbp fwd sendto %u.%u: %m",
483                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
484                 return 0;
485             }
486         }
487         /*FALL THROUGH*/
488
489     case NBPOP_LKUP :
490         /* search our data */
491         n = i = 0;
492         data = packet + 1 + SZ_NBPHDR;
493         end = packet + sizeof( packet );
494
495         for ( ntab = nbptab; ntab; ntab = ntab->nt_next ) {
496             /* don't send out entries if we don't want to route. */
497             if ((ap->ap_iface != ntab->nt_iface) && 
498                 (ntab->nt_iface->i_flags & IFACE_ISROUTER) == 0) {
499               continue;
500             }
501
502             if ( nn.nn_objlen != 1 || *nn.nn_obj != '=' ) {
503                 if ( ntab->nt_nve.nn_objlen != nn.nn_objlen ||
504                         strndiacasecmp( ntab->nt_nve.nn_obj, nn.nn_obj,
505                         nn.nn_objlen )) {
506                     continue;
507                 }
508             }
509
510             if ( nn.nn_typelen != 1 || *nn.nn_type != '=' ) {
511                 if ( ntab->nt_nve.nn_typelen != nn.nn_typelen ||
512                         strndiacasecmp( ntab->nt_nve.nn_type, nn.nn_type,
513                         nn.nn_typelen )) {
514                     continue;
515                 }
516             }
517
518             if ( nn.nn_zonelen != 0 &&
519                     ( nn.nn_zonelen != 1 || *nn.nn_zone != '*' )) {
520                 if ( ntab->nt_nve.nn_zonelen == 0 ||
521                         ( ntab->nt_nve.nn_zonelen == 1 &&
522                         *ntab->nt_nve.nn_zone == '*' )) {
523                     if ( interfaces->i_next->i_rt->rt_zt ) {
524                         zt = (struct ziptab *)interfaces->i_next->i_rt->
525                                 rt_zt->l_data;
526                         if ( zt->zt_len != nn.nn_zonelen ||
527                                 strndiacasecmp( zt->zt_name, nn.nn_zone,
528                                 zt->zt_len )) {
529                             continue;
530                         }
531                     }
532                 } else {
533                     if ( ntab->nt_nve.nn_zonelen != nn.nn_zonelen ||
534                             strndiacasecmp( ntab->nt_nve.nn_zone, nn.nn_zone,
535                             nn.nn_zonelen )) {
536                         continue;
537                     }
538                 }
539             }
540
541             /*
542              * Another tuple won't fit. Send what we've already
543              * got, and start the next packet.
544              */
545             if ( data + SZ_NBPTUPLE + 3 + ntab->nt_nve.nn_objlen +
546                     ntab->nt_nve.nn_typelen + ntab->nt_nve.nn_zonelen > end ) {
547                 nh.nh_op = NBPOP_LKUPREPLY;
548                 nh.nh_cnt = n;
549                 cc = data - packet;
550                 data = packet;
551                 *data++ = DDPTYPE_NBP;
552                 bcopy( &nh, data, SZ_NBPHDR );
553
554                 if ( sendto( ap->ap_fd, packet, cc, 0,
555                         (struct sockaddr *)&nn.nn_sat,
556                         sizeof( struct sockaddr_at )) < 0 ) {
557                     syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
558                             ntohs( nn.nn_sat.sat_addr.s_net ),
559                             nn.nn_sat.sat_addr.s_node );
560                     return 0;
561                 }
562
563                 n = 0;
564                 data = packet + 1 + SZ_NBPHDR;
565                 end = packet + sizeof( packet );
566             }
567
568             nt.nt_net = ntab->nt_nve.nn_sat.sat_addr.s_net;
569             nt.nt_node = ntab->nt_nve.nn_sat.sat_addr.s_node;
570             nt.nt_port = ntab->nt_nve.nn_sat.sat_port;
571             /*
572              * Right now, we'll just give each name a unique enum.  In
573              * the future, we might need to actually assign and save
574              * an enum, based on the associated address.  For the moment,
575              * the enums will be unique and constant, since the order
576              * is fixed.
577              */
578             nt.nt_enum = i++;
579
580             memcpy( data, &nt, SZ_NBPTUPLE );
581             data += SZ_NBPTUPLE;
582
583             *data++ = ntab->nt_nve.nn_objlen;
584             memcpy( data, ntab->nt_nve.nn_obj, ntab->nt_nve.nn_objlen );
585             data += ntab->nt_nve.nn_objlen;
586
587             *data++ = ntab->nt_nve.nn_typelen;
588             memcpy(data, ntab->nt_nve.nn_type, ntab->nt_nve.nn_typelen );
589             data += ntab->nt_nve.nn_typelen;
590
591             /*
592              * Macs won't see something with a zone of 0 length.  We
593              * will always return '*' instead.  Perhaps we should
594              * unconditionally return the real zone?
595              */
596             if ( ntab->nt_nve.nn_zonelen ) {
597                 *data++ = ntab->nt_nve.nn_zonelen;
598                 bcopy( ntab->nt_nve.nn_zone, data, ntab->nt_nve.nn_zonelen );
599                 data += ntab->nt_nve.nn_zonelen;
600             } else {
601                 *data++ = 1;
602                 *data++ = '*';
603             }
604
605             n++;
606         }
607
608         if ( n != 0 ) {
609             nh.nh_op = NBPOP_LKUPREPLY;
610             nh.nh_cnt = n;
611             cc = data - packet;
612             data = packet;
613             *data++ = DDPTYPE_NBP;
614             bcopy( &nh, data, SZ_NBPHDR );
615
616             if ( sendto( ap->ap_fd, packet, cc, 0,
617                     (struct sockaddr *)&nn.nn_sat,
618                     sizeof( struct sockaddr_at )) < 0 ) {
619                 syslog( LOG_ERR, "nbp lkup sendto %u.%u: %m",
620                         ntohs( nn.nn_sat.sat_addr.s_net ),
621                         nn.nn_sat.sat_addr.s_node );
622                 return 0;
623             }
624         }
625         break;
626
627     default :
628         syslog( LOG_INFO, "nbp_packet: bad op (%d)", nh.nh_op );
629         return 1;
630     }
631
632     return 0;
633 }