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