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