#include #include #include #include "babd.h" #include "ctrlfd.h" #include "ippool.h" #include "link.h" typedef struct ip_address{ LIST_ENTRY(ip_address) ptr; unsigned int address; void *ident; } ip_address_t; typedef LIST_HEAD(ip_pool_head, ip_address) ip_pool_head_t; typedef struct dynamic_pool{ LIST_ENTRY(dynamic_pool) ptr; char name[MAX_NAME_LENGTH]; ip_pool_head_t ip_list; ip_pool_head_t in_use; } dynamic_pool_t; typedef LIST_HEAD(dynamic_pool_head, dynamic_pool) dynamic_pool_head_t; /* IP pool pointer */ dynamic_pool_head_t ip_pool; void print_pool(ctrlfd_t *cfd) { dynamic_pool_t *temp1 = ip_pool.lh_first; ip_address_t *temp2; while(temp1 != NULL) { cfd->printf("Pool: %s\n", temp1->name); temp2 = temp1->ip_list.lh_first; while(temp2 != NULL) { cfd->printf(" %s\n", iptostr(temp2->address)); temp2 = temp2->ptr.le_next; } temp1 = temp1->ptr.le_next; } cfd->done(0); } static ip_pool_head_t *shuffle_ip(ip_pool_head_t *include, ip_pool_head_t *exclude) { ip_address_t *cur_include, *cur_exclude, *rem_inc; if(include->lh_first == NULL) { /* No includes in last range def'n -- error */ return (NULL); } else if(exclude->lh_first == NULL) { /* No ip addresses to exclude */ return (include); } else { /* Must exclude some ip address */ cur_exclude = exclude->lh_first; while(cur_exclude != NULL) { cur_include = include->lh_first; while(cur_include != NULL) { if(cur_exclude->address == cur_include->address) { /* Remove this ip address */ rem_inc = cur_include; cur_include = cur_include->ptr.le_next; LIST_REMOVE(rem_inc, ptr); delete rem_inc; break; } else { /* Go on to next address */ cur_include = cur_include->ptr.le_next; } } LIST_REMOVE(cur_exclude, ptr); delete cur_exclude; cur_exclude = exclude->lh_first; } return (include); } /* If we get here, something went wrong! */ return (NULL); } /* * Read a configuration from the config file and validate * the users credentials */ int parse_dynamic(void) { FILE *dyn_file = fopen(dynamicFile, "r"); int l_count = 0; char entry[256]; char nstr_buf[1024]; char *pstr, *nstr, *tstr; unsigned int begin_ip, end_ip, i; dynamic_pool_t *new_pool = NULL; ip_address_t *cur_include, *cur_exclude; char *beg, *end; /* list headers */ ip_pool_head_t include_pool_head; ip_pool_head_t exclude_pool_head; dynamic_pool_head_t new_pool_head; /* Initialize lists */ LIST_INIT(&ip_pool); LIST_INIT(&exclude_pool_head); LIST_INIT(&include_pool_head); LIST_INIT(&new_pool_head); if (dyn_file == NULL) { if (-1 == dyn_ip_enabled) { dyn_ip_enabled = 0; return 0; } syslog(LOG_ERR, "Error opening config file %s",dynamicFile); return -1; } while (!feof(dyn_file)) { memset(entry, '\0', 256); l_count++; fgets(entry, 256, dyn_file); if (strlen(entry)) entry[strlen(entry) - 1] = '\0'; syslog(LOG_DEBUG, "%d: %s", l_count, entry); /* * Filter out comments and blanks */ if((entry[0] == '#') || (strlen(entry) == 0)) continue; pstr = nstr = nstr_buf; memset(nstr, '\0', strlen(entry) * 2); for (tstr = entry; *tstr != '\0'; tstr++) { if((*tstr != ' ') && (*tstr != '\t')) { *pstr = *tstr; pstr++; } } *pstr = '\0'; pstr = nstr; /* * Look for 'range' tag */ if (0 == strncasecmp(pstr, RANGE_TAG, strlen(RANGE_TAG))) { if (new_pool == NULL) { /* * We have a new range and we don't need * to sort out inc/exc from last range. */ pstr += strlen(RANGE_TAG); new_pool = new dynamic_pool_t; if (NULL == new_pool) { syslog(LOG_ERR, "Out of memory reading config file"); return -1; } LIST_INIT(&new_pool->ip_list); LIST_INIT(&new_pool->in_use); strncpy(new_pool->name, pstr, MAX_NAME_LENGTH); } else { /* * We have a new pool to deal with but must queue the old * one first */ if(NULL == shuffle_ip(&include_pool_head, &exclude_pool_head)) { syslog(LOG_ERR, "Error in config file"); return -1; } new_pool->ip_list.lh_first = include_pool_head.lh_first; include_pool_head.lh_first->ptr.le_prev = &new_pool->ip_list.lh_first; if(ip_pool.lh_first == NULL) { LIST_INSERT_HEAD(&ip_pool, new_pool, ptr); } else { LIST_INSERT_AFTER(ip_pool.lh_first, new_pool, ptr); } LIST_INIT(&include_pool_head); LIST_INIT(&exclude_pool_head); /* * Now that we've got the previous pool out of the way * deal with the next range */ pstr += strlen(RANGE_TAG); new_pool = new dynamic_pool_t; if (NULL == new_pool) { syslog(LOG_ERR, "Out of memory reading config file"); return -1; } LIST_INIT(&new_pool->ip_list); LIST_INIT(&new_pool->in_use); strncpy(new_pool->name, pstr, MAX_NAME_LENGTH); } continue; } else if((0 == strncasecmp(pstr, INCLUDE_TAG, strlen(INCLUDE_TAG))) && (new_pool != NULL)) { pstr += strlen(INCLUDE_TAG); if(NULL == (beg = strtok(pstr, "-"))) return -1; end = strtok(NULL, "-"); begin_ip = strtoip(beg); if (!begin_ip || (begin_ip == ~0U)) { syslog(LOG_ERR, "Invalid beginning address for ip pool '%s'", beg); continue; } if(end != NULL) end_ip = strtoip(end); else end_ip = begin_ip; if (!end_ip || (end_ip == ~0U)) { syslog(LOG_ERR, "Invalid ending address for ip pool '%s'", beg); continue; } if ((end_ip - begin_ip) > 65536) { syslog(LOG_ERR, "ip pool range of %u ips from %s to %s is too big!", end_ip - begin_ip, iptostr(begin_ip), iptostr(end_ip)); continue; } if (NULL == include_pool_head.lh_first) { /* * We're dealing with the first include * batch. */ cur_include = new ip_address_t; if (NULL == cur_include) { syslog(LOG_ERR, "Out of memory reading ip config file"); return -1; } LIST_INSERT_HEAD(&include_pool_head, cur_include, ptr); cur_include->address = begin_ip; cur_include->ident = 0; begin_ip++; } for(i = begin_ip; i <= end_ip; i++) { cur_include = new ip_address_t; if (NULL == cur_include) { syslog(LOG_ERR, "Out of memory reading ip config file"); return -1; } cur_include->address = i; cur_include->ident = 0; LIST_INSERT_AFTER(include_pool_head.lh_first, cur_include, ptr); } continue; } else if((0 == strncasecmp(pstr, EXCLUDE_TAG, strlen(EXCLUDE_TAG))) && (new_pool != NULL)) { pstr += strlen(EXCLUDE_TAG); if(NULL == (beg = strtok(pstr, "-"))) return -1; end = strtok(NULL, "-"); begin_ip = strtoip(beg); if (!begin_ip || (begin_ip == ~0U)) { syslog(LOG_ERR, "Invalid beginning address for ip pool exclude '%s'", beg); continue; } if(end != NULL) end_ip = strtoip(end); else end_ip = begin_ip; if (!end_ip || (end_ip == ~0U)) { syslog(LOG_ERR, "Invalid ending address for ip pool exclude '%s'", beg); continue; } if ((end_ip - begin_ip) > 65536) { syslog(LOG_ERR, "ip pool range of %u ips from %s to %s is too big!", end_ip - begin_ip, iptostr(begin_ip), iptostr(end_ip)); continue; } if(NULL == exclude_pool_head.lh_first) { /* * We're dealing with the first exclude * batch. */ cur_exclude = new ip_address_t; if (NULL == cur_exclude) { syslog(LOG_ERR, "Out of memory reading ip config file"); return -1; } cur_exclude->address = begin_ip; cur_exclude->ident = 0; LIST_INSERT_HEAD(&exclude_pool_head, cur_exclude, ptr); begin_ip++; } for(i = begin_ip; i <= end_ip; i++) { cur_exclude = new ip_address_t; if (NULL == cur_exclude) { syslog(LOG_ERR, "Out of memory reading ip config file"); return -1; } cur_exclude->address = i; cur_exclude->ident = 0; LIST_INSERT_AFTER(exclude_pool_head.lh_first, cur_exclude, ptr); } // free(nstr); continue; } else { syslog(LOG_ERR, "Parse error on config file line %d.", l_count); return -1; } } /* * Unfortunately we have to make sure that we don't need to collate(??) * one final round of inc/exc ip addresses */ if(new_pool != NULL) { if(NULL == shuffle_ip(&include_pool_head, &exclude_pool_head)) { syslog(LOG_ERR, "Error in config file"); return -1; } /* * Get around some LIST_ problems and insert the new * ip list into the pool. */ new_pool->ip_list.lh_first = include_pool_head.lh_first; include_pool_head.lh_first->ptr.le_prev = &new_pool->ip_list.lh_first; if(ip_pool.lh_first == NULL) { LIST_INSERT_HEAD(&ip_pool, new_pool, ptr); } else { LIST_INSERT_AFTER(ip_pool.lh_first, new_pool, ptr); } /* No longer need the new_pool pointer, so reset it */ LIST_INIT(&include_pool_head); LIST_INIT(&exclude_pool_head); new_pool = NULL; } return 0; } unsigned int request_ip_address(const char *name, void *id) { dynamic_pool_t *current = ip_pool.lh_first; ip_address_t *found_ip; unsigned int addr; while(current) { if(0 == strncasecmp(current->name, name, MAX_NAME_LENGTH)) { /* * We've found a match for the pool so now * grab the first free ip address */ found_ip = current->ip_list.lh_first; if(NULL != found_ip) { /* * Not NULL so we have at lease one * address to assign. */ addr = found_ip->address; LIST_REMOVE(found_ip, ptr); found_ip->ident = id; if(current->in_use.lh_first == NULL) { LIST_INSERT_HEAD(¤t->in_use, found_ip, ptr); } else { LIST_INSERT_AFTER(current->in_use.lh_first, found_ip, ptr); } return (addr); } else return 0; } else { /* Go on to next */ current = current->ptr.le_next; } } return 0; } void release_ip_address(unsigned ip, void *id) { dynamic_pool_t *current = ip_pool.lh_first; ip_address_t *curr_ip, *new_ip; while(current) { /* * We've found a match for the pool so now * find the id. */ curr_ip = current->in_use.lh_first; while((curr_ip != NULL) && (curr_ip->ident != id)) { curr_ip = curr_ip->ptr.le_next; } if(curr_ip != NULL) { /* * Found the in use IP */ LIST_REMOVE(curr_ip, ptr); curr_ip->ident = 0; if(current->ip_list.lh_first == NULL) { LIST_INSERT_HEAD(¤t->ip_list, curr_ip, ptr); } else { /* In the interest of good re-use, add the IP to the end */ new_ip = current->ip_list.lh_first; while(new_ip->ptr.le_next != NULL) new_ip = new_ip->ptr.le_next; LIST_INSERT_AFTER(new_ip, curr_ip, ptr); } return; } else { /* Go on to next */ current = current->ptr.le_next; } } } ippool_request_t::ippool_request_t(const char *pool, ippool_requestor_t *req, const char *name) { m_pool = pool; m_requestor = req; m_username = name; g_cluster->cluster_req(this); } void ippool_request_t::build_pkt(struct bcluster_packet *pkt) { pkt->u.request.request_type = BCLUSTER_REQ_IPPOOL_REQ; strncpy(pkt->u.request.pool, m_pool, sizeof(pkt->u.request.pool)); if (m_username) strncpy(pkt->u.request.user, m_username, sizeof(pkt->u.request.user)); bcluster_req_t::build_pkt(pkt); } void bcluster_ippool_request(bcluster_peer_t *peer, struct bcluster_packet *pkt) { const char *user = pkt->u.request.user[0] ? pkt->u.request.user : NULL; unsigned id = pkt->u.request.id; if (user) lcp_probe_user(user); u32 ip = request_ip_address(pkt->u.request.pool, NULL); memset(pkt, 0, sizeof(*pkt)); pkt->hdr.len = sizeof(*pkt); pkt->hdr.type = BCLUSTER_PACKET_TYPE_RESPONSE; pkt->hdr.magic = BCLUSTER_PACKET_MAGIC; pkt->u.response.request_type = BCLUSTER_REQ_IPPOOL_REQ; pkt->u.response.id = id; pkt->u.response.ip = ip; peer->send_pkt(pkt); } void ippool_request_t::rx_response(bcluster_peer_t *peer, struct bcluster_packet *pkt) { m_requestor->ippool_response(pkt->u.response.ip); } void ippool_request_t::master_get_response(void) { m_response = request_ip_address(m_pool, NULL); }