static void msg_nmbd_send_packet(struct messaging_context *msg, void *private_data, uint32_t msg_type, struct server_id src, DATA_BLOB *data) { struct packet_struct *p = (struct packet_struct *)data->data; struct subnet_record *subrec; struct sockaddr_storage ss; const struct sockaddr_storage *pss; const struct in_addr *local_ip; DEBUG(10, ("Received send_packet from %u\n", (unsigned int)procid_to_pid(&src))); if (data->length != sizeof(struct packet_struct)) { DEBUG(2, ("Discarding invalid packet length from %u\n", (unsigned int)procid_to_pid(&src))); return; } if ((p->packet_type != NMB_PACKET) && (p->packet_type != DGRAM_PACKET)) { DEBUG(2, ("Discarding invalid packet type from %u: %d\n", (unsigned int)procid_to_pid(&src), p->packet_type)); return; } in_addr_to_sockaddr_storage(&ss, p->ip); pss = iface_ip((struct sockaddr *)(void *)&ss); if (pss == NULL) { DEBUG(2, ("Could not find ip for packet from %u\n", (unsigned int)procid_to_pid(&src))); return; } local_ip = &((const struct sockaddr_in *)pss)->sin_addr; subrec = FIRST_SUBNET; p->recv_fd = -1; p->send_fd = (p->packet_type == NMB_PACKET) ? subrec->nmb_sock : subrec->dgram_sock; for (subrec = FIRST_SUBNET; subrec != NULL; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { if (ip_equal_v4(*local_ip, subrec->myip)) { p->send_fd = (p->packet_type == NMB_PACKET) ? subrec->nmb_sock : subrec->dgram_sock; break; } } if (p->packet_type == DGRAM_PACKET) { p->port = 138; p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr; p->packet.dgram.header.source_port = 138; } send_packet(p); }
void check_master_browser_exists(time_t t) { static time_t lastrun=0; struct subnet_record *subrec; const char *workgroup_name = lp_workgroup(); if (!lastrun) lastrun = t; if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60))) return; lastrun = t; dump_workgroups(False); for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work)) { /* Do a name query for the local master browser on this net. */ query_name( subrec, work->work_group, 0x1d, check_for_master_browser_success, check_for_master_browser_fail, NULL); } } } }
static void wins_next_registration(struct response_record *rrec) { struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; struct nmb_name *nmbname = &sent_nmb->question.question_name; uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata); struct userdata_struct *userdata = rrec->userdata; const char *tag; struct in_addr last_ip; struct subnet_record *subrec; putip(&last_ip,&sent_nmb->additional->rdata[2]); if (!userdata) { /* it wasn't multi-homed */ return; } tag = (const char *)userdata->data; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { if (ip_equal(last_ip, subrec->myip)) { subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec); break; } } if (!subrec) { /* no more to do! */ return; } switch (sent_nmb->header.opcode) { case NMB_NAME_MULTIHOMED_REG_OPCODE: multihomed_register_one(nmbname, nb_flags, NULL, NULL, subrec->myip, tag); break; case NMB_NAME_REFRESH_OPCODE_8: queue_wins_refresh(nmbname, register_name_response, register_name_timeout_response, nb_flags, subrec->myip, tag); break; } }
static void msg_nmbd_send_packet(int msg_type, struct process_id src, void *buf, size_t len, void *private_data) { struct packet_struct *p = (struct packet_struct *)buf; struct subnet_record *subrec; struct in_addr *local_ip; DEBUG(10, ("Received send_packet from %d\n", procid_to_pid(&src))); if (len != sizeof(struct packet_struct)) { DEBUG(2, ("Discarding invalid packet length from %d\n", procid_to_pid(&src))); return; } if ((p->packet_type != NMB_PACKET) && (p->packet_type != DGRAM_PACKET)) { DEBUG(2, ("Discarding invalid packet type from %d: %d\n", procid_to_pid(&src), p->packet_type)); return; } local_ip = iface_ip(p->ip); if (local_ip == NULL) { DEBUG(2, ("Could not find ip for packet from %d\n", procid_to_pid(&src))); return; } subrec = FIRST_SUBNET; p->fd = (p->packet_type == NMB_PACKET) ? subrec->nmb_sock : subrec->dgram_sock; for (subrec = FIRST_SUBNET; subrec != NULL; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { if (ip_equal(*local_ip, subrec->myip)) { p->fd = (p->packet_type == NMB_PACKET) ? subrec->nmb_sock : subrec->dgram_sock; break; } } if (p->packet_type == DGRAM_PACKET) { p->port = 138; p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr; p->packet.dgram.header.source_port = 138; } send_packet(p); }
void run_elections(time_t t) { static time_t lastime = 0; struct subnet_record *subrec; /* Send election packets once every 2 seconds - note */ if (lastime && (t - lastime < 2)) return; lastime = t; START_PROFILE(run_elections); for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { if (work->RunningElection) { /* * We can only run an election for a workgroup if we have * registered the WORKGROUP<1e> name, as that's the name * we must listen to. */ struct nmb_name nmbname; make_nmb_name(&nmbname, work->work_group, 0x1e); if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) { DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \ yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name )); continue; } send_election_dgram(subrec, work->work_group, work->ElectionCriterion, t - StartupTime, global_myname); if (work->ElectionCount++ >= 4) { /* Won election (4 packets were sent out uncontested. */ DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n", work->work_group, subrec->subnet_name )); work->RunningElection = False; become_local_master_browser(subrec, work); } } } }
void load_lmhosts_file(const char *fname) { char *name = NULL; int name_type; struct sockaddr_storage ss; TALLOC_CTX *ctx = talloc_init("load_lmhosts_file"); FILE *fp = startlmhosts( fname ); if (!fp) { DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n", fname, strerror(errno))); TALLOC_FREE(ctx); return; } while (getlmhostsent(ctx, fp, &name, &name_type, &ss) ) { struct in_addr ipaddr; struct subnet_record *subrec = NULL; enum name_source source = LMHOSTS_NAME; if (ss.ss_family != AF_INET) { TALLOC_FREE(name); continue; } ipaddr = ((struct sockaddr_in *)&ss)->sin_addr; /* We find a relevent subnet to put this entry on, then add it. */ /* Go through all the broadcast subnets and see if the mask matches. */ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { if(same_net_v4(ipaddr, subrec->bcast_ip, subrec->mask_ip)) break; } /* If none match add the name to the remote_broadcast_subnet. */ if(subrec == NULL) subrec = remote_broadcast_subnet; if(name_type == -1) { /* Add the (0) and (0x20) names directly into the namelist for this subnet. */ (void)add_name_to_subnet(subrec,name,0x00,(uint16_t)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr); (void)add_name_to_subnet(subrec,name,0x20,(uint16_t)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr); } else { /* Add the given name type to the subnet namelist. */ (void)add_name_to_subnet(subrec,name,name_type,(uint16_t)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr); } } TALLOC_FREE(ctx); endlmhosts(fp); }
void tell_become_backup(void) { struct subnet_record *subrec; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { struct server_record *servrec; int num_servers = 0; int num_backups = 0; for (servrec = work->serverlist; servrec; servrec = servrec->next) { num_servers++; if (is_myname(servrec->serv.name)) continue; if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER) { num_backups++; continue; } if (servrec->serv.type & SV_TYPE_MASTER_BROWSER) continue; if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue; DEBUG(3,("num servers: %d num backups: %d\n", num_servers, num_backups)); /* make first server a backup server. thereafter make every tenth server a backup server */ if (num_backups != 0 && (num_servers+9) / num_backups > 10) continue; DEBUG(2,("sending become backup to %s %s for %s\n", servrec->serv.name, inet_ntoa(subrec->bcast_ip), work->work_group)); /* type 11 request from MYNAME(20) to WG(1e) for SERVER */ do_announce_request(servrec->serv.name, work->work_group, ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip); } } } }
void announce_my_servers_removed(void) { int announce_interval = lp_lm_interval(); int lm_announce = lp_lm_announce(); struct subnet_record *subrec; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { struct server_record *servrec; work->announce_interval = 0; for (servrec = work->serverlist; servrec; servrec = servrec->next) { if (!is_myname(servrec->serv.name)) continue; servrec->serv.type = 0; if(AM_LOCAL_MASTER_BROWSER(work)) send_local_master_announcement(subrec, work, servrec); send_host_announcement(subrec, work, servrec); if ((announce_interval <= 0) || (lm_announce <= 0)) { /* user absolutely does not want LM announcements to be sent. */ continue; } if ((lm_announce >= 2) && (!found_lm_clients)) { /* has been set to 2 (Auto) but no LM clients detected (yet). */ continue; } /* * lm announce was set or we have seen lm announcements, so do * a lm announcement of host removed. */ send_lm_host_announcement(subrec, work, servrec, 0); } } } }
/**************************************************************************** Load a lmhosts file. ****************************************************************************/ void load_lmhosts_file(char *fname) { pstring name; int name_type; struct in_addr ipaddr; FILE *fp = startlmhosts( fname ); if (!fp) { DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n", fname, strerror(errno))); return; } while (getlmhostsent(fp, name, &name_type, &ipaddr) ) { struct subnet_record *subrec = NULL; enum name_source source = LMHOSTS_NAME; /* We find a relevent subnet to put this entry on, then add it. */ /* Go through all the broadcast subnets and see if the mask matches. */ for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { if(same_net(ipaddr, subrec->bcast_ip, subrec->mask_ip)) break; } /* If none match add the name to the remote_broadcast_subnet. */ if(subrec == NULL) subrec = remote_broadcast_subnet; if(name_type == -1) { /* Add the (0) and (0x20) names directly into the namelist for this subnet. */ (void)add_name_to_subnet(subrec,name,0x00,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr); (void)add_name_to_subnet(subrec,name,0x20,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr); } else { /* Add the given name type to the subnet namelist. */ (void)add_name_to_subnet(subrec,name,name_type,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr); } } endlmhosts(fp); }
void announce_my_lm_server_names(time_t t) { struct subnet_record *subrec; static time_t last_lm_announce_time=0; int announce_interval = lp_lm_interval(); int lm_announce = lp_lm_announce(); if ((announce_interval <= 0) || (lm_announce <= 0)) { /* user absolutely does not want LM announcements to be sent. */ return; } if ((lm_announce >= 2) && (!found_lm_clients)) { /* has been set to 2 (Auto) but no LM clients detected (yet). */ return; } /* Otherwise: must have been set to 1 (Yes), or LM clients *have* been detected. */ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup); if(work) { struct server_record *servrec; if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval )) continue; last_lm_announce_time = t; for (servrec = work->serverlist; servrec; servrec = servrec->next) { if (is_myname(servrec->serv.name)) /* skipping equivalent of announce_server() */ send_lm_host_announcement(subrec, work, servrec, announce_interval); } } /* if work */ } /* for subrec */ }
void announce_myself_to_domain_master_browser(time_t t) { struct subnet_record *subrec; struct work_record *work; if(!we_are_a_wins_client()) { DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n")); return; } if (!announce_timer_last) announce_timer_last = t; if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60)) { DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n", (int)t, (int)announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 )); return; } announce_timer_last = t; /* Look over all our broadcast subnets to see if any of them has the state set as local master browser. */ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { for (work = subrec->workgrouplist; work; work = work->next) { if (AM_LOCAL_MASTER_BROWSER(work)) { DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \ workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name)); /* Look in nmbd_browsersync.c for the rest of this code. */ announce_and_sync_with_domain_master_browser(subrec, work); } } } }
void announce_my_server_names(time_t t) { struct subnet_record *subrec; for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup); if(work) { struct server_record *servrec; if (work->needannounce) { /* Drop back to a max 3 minute announce. This is to prevent a single lost packet from breaking things for too long. */ work->announce_interval = MIN(work->announce_interval, CHECK_TIME_MIN_HOST_ANNCE*60); work->lastannounce_time = t - (work->announce_interval+1); work->needannounce = False; } /* Announce every minute at first then progress to every 12 mins */ if ((t - work->lastannounce_time) < work->announce_interval) continue; if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60)) work->announce_interval += 60; work->lastannounce_time = t; for (servrec = work->serverlist; servrec; servrec = servrec->next) { if (is_myname(servrec->serv.name)) announce_server(subrec, work, servrec); } } /* if work */ } /* for subrec */ }
static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags, register_name_success_function success_fn, register_name_fail_function fail_fn) { /* If we are adding a group name, we just send multiple register name packets to the WINS server (this is an internet group name. If we are adding a unique name, We need first to add our names to the unicast subnet namelist. This is because when a WINS server receives a multihomed registration request, the first thing it does is to send a name query to the registering machine, to see if it has put the name in it's local namelist. We need the name there so the query response code in nmbd_incomingrequests.c will find it. We are adding this name prematurely (we don't really have it yet), but as this is on the unicast subnet only we will get away with this (only the WINS server will ever query names from us on this subnet). */ int num_ips=0; int i, t; struct subnet_record *subrec; char **wins_tags; struct in_addr *ip_list; unstring name; for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) num_ips++; if((ip_list = SMB_MALLOC_ARRAY(struct in_addr, num_ips))==NULL) { DEBUG(0,("multihomed_register_name: malloc fail !\n")); return; } for (subrec = FIRST_SUBNET, i = 0; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) { ip_list[i] = subrec->myip; } pull_ascii_nstring(name, sizeof(name), nmbname->name); add_name_to_subnet(unicast_subnet, name, nmbname->name_type, nb_flags, lp_max_ttl(), SELF_NAME, num_ips, ip_list); /* get the list of wins tags - we try to register for each of them */ wins_tags = wins_srv_tags(); /* Now try and register the name for each wins tag. Note that at this point we only register our first IP with each wins group. We will register the rest from wins_next_registration() when we get the reply for this one. That follows the way W2K does things (tridge) */ for (t=0; wins_tags && wins_tags[t]; t++) { multihomed_register_one(nmbname, nb_flags, success_fn, fail_fn, ip_list[0], wins_tags[t]); } wins_srv_tags_free(wins_tags); SAFE_FREE(ip_list); }