Пример #1
0
/*
 * dhcp_lookup_dd: perform lookup_dd.
 */
static int
dhcp_lookup_dd(dsvc_handle_t hand, boolean_t partial, uint_t query,
    int count, const void *targetp, void **recordsp, uint_t *nrecordsp)
{
#ifndef	DEBUG
	return (lookup_dd(hand, partial, query, count, targetp, recordsp,
	    nrecordsp));

#else	/* DEBUG */
	int		ret;
	int 		hind = (int)hand;
	int 		ind;
	dn_rec_t	*inp;
	dn_rec_list_t	**outp = (dn_rec_list_t **)recordsp;
	dbg_t		*dbp;
	dbg_t		*endp;
	dbg_rec_t	*rp;
	dn_rec_t	*recp;
	dn_rec_list_t	*reclp;
	dbg_t		*dbg_db;

	if (dbg_net && hind >= 0 && hind < DBG_MAXTABLE) {
		dbg_db = (dbg_t *)dbg_handle[hind];

		if (outp)
			*outp = NULL;
		if (nrecordsp)
			*nrecordsp = 0;
		inp = (dn_rec_t *)targetp;

		(void) rw_rdlock(&dbg_lock[hind]);
		/*
		 * Simple linear search, aided by the fact that
		 * the server currently checks flags.
		 */
		if (DSVC_QISEQ(query, DN_QCIP)) {
			ind = inp->dn_cip.s_addr & dbg_mask;
			dbp = &dbg_db[ind];
			endp = &dbg_db[ind + 1];
		} else {
			ind = 0;
			dbp = dbg_db;
			endp = &dbg_db[dbg_size];
		}
		for (; dbp < endp; dbp++, ind++) {
			/*
			 * Initialize record. fields will be zero'd
			 * when initially mmap'd.
			 */
			if (dbp->dn_cid_len == 0) {
				/* Skip server address to avoid arp issues. */
				if (ind == (ntohl(server_ip.s_addr) % 256))
					continue;
				if (dbg_cid)
					(void) snprintf(dbp->dn_cid,
					    sizeof (dbp->dn_cid), "%8X",
					    dbg_cid++);
				dbp->dn_flags = dbg_flags;
				dbp->dn_lease = dbg_lease;
				dbp->dn_macro[0] = dbg_macro;
				dbp->dn_macro[1] = '\0';
				dbp->dn_cid_len = 1;
			}
			if (DSVC_QISEQ(query, DN_QCID) &&
			    (inp->dn_cid[0] != dbp->dn_cid[0] ||
			    memcmp(dbp->dn_cid, inp->dn_cid, inp->dn_cid_len)))
				continue;

			rp = (dbg_rec_t *)smalloc(sizeof (dbg_rec_t));
			reclp = &rp->d_reclist;
			recp = &rp->d_rec;

			if (nrecordsp)
				(*nrecordsp)++;

			reclp->dnl_rec = recp;
			recp->dn_lease = dbp->dn_lease;
			recp->dn_sip.s_addr = ntohl(owner_ip->s_addr);
			recp->dn_cip.s_addr = 0xd000000 + (hind << 16) + ind;
			recp->dn_cid_len = dbp->dn_cid_len;
			recp->dn_flags = dbp->dn_flags;
			recp->dn_macro[0] = dbp->dn_macro[0];
			recp->dn_macro[1] = '\0';
			if ((recp->dn_cid[0] = dbp->dn_cid[0]) != '\0')
				(void) memcpy(recp->dn_cid, dbp->dn_cid,
				    dbp->dn_cid_len);
			if (*outp == NULL)
				*outp = reclp;
			else {
				reclp->dnl_next = *outp;
				*outp = reclp;
			}
			if (count > 0 && nrecordsp && *nrecordsp >= count)
				break;
		}
		(void) rw_unlock(&dbg_lock[hind]);
		ret = DSVC_SUCCESS;
	} else
		ret = lookup_dd(hand, partial, query, count, targetp,
		    recordsp, nrecordsp);

	return (ret);
#endif	/* DEBUG */
}
Пример #2
0
/*
 * Compares the fields in fields[] agains the fields in target `targetp',
 * using `query' to decide what fields to compare.  Returns B_TRUE if `dnp'
 * matches `targetp', B_FALSE if not.  On success, `dnp' is completely
 * filled in.
 */
static boolean_t
record_match(char *fields[], dn_rec_t *dnp, const dn_rec_t *targetp,
    uint_t query)
{
	unsigned int	qflags[] = { DN_QFDYNAMIC, DN_QFAUTOMATIC, DN_QFMANUAL,
				    DN_QFUNUSABLE, DN_QFBOOTP_ONLY };
	unsigned int	flags[]  = { DN_FDYNAMIC, DN_FAUTOMATIC, DN_FMANUAL,
				    DN_FUNUSABLE, DN_FBOOTP_ONLY };
	unsigned int	i;
	uint_t		dn_cid_len;

	dnp->dn_cip.s_addr = ntohl(inet_addr(fields[DNF_CIP]));
	if (DSVC_QISEQ(query, DN_QCIP) &&
	    dnp->dn_cip.s_addr != targetp->dn_cip.s_addr)
		return (B_FALSE);
	if (DSVC_QISNEQ(query, DN_QCIP) &&
	    dnp->dn_cip.s_addr == targetp->dn_cip.s_addr)
		return (B_FALSE);

	dnp->dn_lease = atoi(fields[DNF_LEASE]);
	if (DSVC_QISEQ(query, DN_QLEASE) && targetp->dn_lease != dnp->dn_lease)
		return (B_FALSE);
	if (DSVC_QISNEQ(query, DN_QLEASE) && targetp->dn_lease == dnp->dn_lease)
		return (B_FALSE);

	/*
	 * We use dn_cid_len since dnp->dn_cid_len is of type uchar_t but
	 * hexascii_to_octet() expects an uint_t *
	 */
	dn_cid_len = DN_MAX_CID_LEN;
	if (hexascii_to_octet(fields[DNF_CID], strlen(fields[DNF_CID]),
	    dnp->dn_cid, &dn_cid_len) != 0)
		return (B_FALSE);

	dnp->dn_cid_len = dn_cid_len;
	if (DSVC_QISEQ(query, DN_QCID) &&
	    (dnp->dn_cid_len != targetp->dn_cid_len ||
	    (memcmp(dnp->dn_cid, targetp->dn_cid, dnp->dn_cid_len) != 0)))
		return (B_FALSE);
	if (DSVC_QISNEQ(query, DN_QCID) &&
	    (dnp->dn_cid_len == targetp->dn_cid_len &&
	    (memcmp(dnp->dn_cid, targetp->dn_cid, dnp->dn_cid_len) == 0)))
		return (B_FALSE);

	dnp->dn_sip.s_addr = ntohl(inet_addr(fields[DNF_SIP]));
	if (DSVC_QISEQ(query, DN_QSIP) &&
	    dnp->dn_sip.s_addr != targetp->dn_sip.s_addr)
		return (B_FALSE);
	if (DSVC_QISNEQ(query, DN_QSIP) &&
	    dnp->dn_sip.s_addr == targetp->dn_sip.s_addr)
		return (B_FALSE);

	unescape('|', fields[DNF_MACRO], dnp->dn_macro, sizeof (dnp->dn_macro));
	if (DSVC_QISEQ(query, DN_QMACRO) &&
	    strcmp(targetp->dn_macro, dnp->dn_macro) != 0)
		return (B_FALSE);
	if (DSVC_QISNEQ(query, DN_QMACRO) &&
	    strcmp(targetp->dn_macro, dnp->dn_macro) == 0)
		return (B_FALSE);

	dnp->dn_flags = atoi(fields[DNF_FLAGS]);
	for (i = 0; i < sizeof (qflags) / sizeof (unsigned int); i++) {
		if (DSVC_QISEQ(query, qflags[i]) &&
		    (dnp->dn_flags & flags[i]) !=
		    (targetp->dn_flags & flags[i]))
			return (B_FALSE);
		if (DSVC_QISNEQ(query, qflags[i]) &&
		    (dnp->dn_flags & flags[i]) ==
		    (targetp->dn_flags & flags[i]))
			return (B_FALSE);
	}

	dnp->dn_sig = atoll(fields[DNF_SIG]);
	unescape('|', fields[DNF_COMMENT], dnp->dn_comment,
	    sizeof (dnp->dn_comment));

	return (B_TRUE);
}
Пример #3
0
/*
 * Internal version of lookup_dt() used by both lookup_dt() and
 * update_dt(); same semantics as lookup_dt() except that the `partial'
 * argument has been generalized into a `flags' field and the handle has
 * been turned into a FILE pointer.
 */
static int
find_dt(FILE *fp, uint_t flags, uint_t query, int count,
    const dt_rec_t *targetp, dt_rec_list_t **recordsp, uint_t *nrecordsp)
{
	int		retval = DSVC_SUCCESS;
	char 		*buf = NULL, *fields[DTF_MAX_FIELDS];
	uint_t		nrecords;
	dt_rec_t	*recordp;
	dt_rec_list_t	*records, *new_records;
	unsigned int	nfields;
	off_t		recoff;

	if (fseek(fp, 0, SEEK_SET) == -1)
		return (DSVC_INTERNAL);

	records = NULL;
	for (nrecords = 0; count < 0 || nrecords < count; ) {
		free(buf);

		if (flags & FIND_POSITION)
			recoff = ftello(fp);

		buf = read_entry(fp);
		if (buf == NULL) {
			if (!feof(fp))
				retval = DSVC_NO_MEMORY;
			break;
		}

		/*
		 * Skip pure comment lines; for now this just skips the
		 * header information at the top of the container.
		 */
		if (buf[0] == DTF_COMMENT_CHAR)
			continue;

		/*
		 * Parse out the entry into the dt_rec_t
		 */
		nfields = field_split(buf, DTF_MAX_FIELDS, fields, " \t");
		if (nfields < DTF_MAX_FIELDS)
			continue;

		/*
		 * See if we've got a match.  If so, allocate the new
		 * record, fill it in, and continue.
		 */
		if (DSVC_QISEQ(query, DT_QTYPE) &&
		    targetp->dt_type != fields[DTF_TYPE][0])
			continue;
		else if (DSVC_QISNEQ(query, DT_QTYPE) &&
		    targetp->dt_type == fields[DTF_TYPE][0])
			continue;

		if (DSVC_QISEQ(query, DT_QKEY) &&
		    strcmp(targetp->dt_key, fields[DTF_KEY]) != 0)
			continue;
		else if (DSVC_QISNEQ(query, DT_QKEY) &&
		    strcmp(targetp->dt_key, fields[DTF_KEY]) == 0)
			continue;

		/*
		 * Caller just wants a count of the number of matching
		 * records, not the records themselves; continue.
		 */
		if (recordsp == NULL) {
			nrecords++;
			continue;
		}

		/*
		 * Allocate record; if FIND_POSITION flag is set, then we
		 * need to allocate an extended (dt_recpos_t) record.
		 */
		if (flags & FIND_POSITION)
			recordp = malloc(sizeof (dt_recpos_t));
		else
			recordp = malloc(sizeof (dt_rec_t));

		if (recordp == NULL) {
			if ((flags & FIND_PARTIAL) == 0)
				retval = DSVC_NO_MEMORY;
			break;
		}

		/*
		 * Fill in record; if FIND_POSITION flag is set, then pass
		 * back additional location information.
		 */
		(void) strlcpy(recordp->dt_key, fields[DTF_KEY],
		    sizeof (recordp->dt_key));
		recordp->dt_sig = 1;
		recordp->dt_type = fields[DTF_TYPE][0];
		recordp->dt_value = strdup(fields[DTF_VALUE]);
		if (recordp->dt_value == NULL) {
			free(recordp);
			if ((flags & FIND_PARTIAL) == 0)
				retval = DSVC_NO_MEMORY;
			break;
		}

		if (flags & FIND_POSITION) {
			((dt_recpos_t *)recordp)->dtp_off = recoff;
			((dt_recpos_t *)recordp)->dtp_size = ftello(fp) -
			    recoff;
		}

		/*
		 * Chuck the record on the list; up the counter.
		 */
		new_records = add_dtrec_to_list(recordp, records);
		if (new_records == NULL) {
			free_dtrec(recordp);
			if ((flags & FIND_PARTIAL) == 0)
				retval = DSVC_NO_MEMORY;
			break;
		}
		records = new_records;
		nrecords++;
	}

	free(buf);

	if (retval == DSVC_SUCCESS) {
		*nrecordsp = nrecords;
		if (recordsp != NULL)
			*recordsp = records;
		return (DSVC_SUCCESS);
	}

	if (records != NULL)
		free_dtrec_list(records);

	return (retval);
}
Пример #4
0
/*
 * Internal version lookup routine used by both lookup_dn() and
 * update_dn(); same semantics as lookup_dn() except that the `partial'
 * argument has been generalized into a `flags' field.
 */
static int
find_dn(int fd, uint_t flags, uint_t query, int count, const dn_rec_t *targetp,
    dn_rec_list_t **recordsp, uint_t *nrecordsp)
{
	int		retval = DSVC_SUCCESS;
	char		*fields[DNF_FIELDS];
	uint_t		nrecords;
	dn_rec_t	dn, *recordp;
	dn_rec_list_t	*records, *new_records;
	unsigned int	nfields;
	struct stat	st;
	struct in_addr	cip_nbo;
	char		*ent0, *ent, *entend;
	char		cip[INET_ADDRSTRLEN + 2];

	/*
	 * Page the whole container into memory via mmap() so we can scan it
	 * quickly; map it MAP_PRIVATE so that we can change newlines to
	 * NULs without changing the actual container itself.
	 */
	if (fstat(fd, &st) == -1 || st.st_size < 1)
		return (DSVC_INTERNAL);

	ent0 = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
	if (ent0 == MAP_FAILED)
		return (DSVC_INTERNAL);

	/*
	 * NUL-terminate the last byte (which should be a newline) so that
	 * we can safely use string functions on the mapped container.
	 */
	ent0[st.st_size - 1] = '\0';

	/*
	 * If we're searching by client IP address, then build a target
	 * string we can use to find it quickly.
	 */
	if (DSVC_QISEQ(query, DN_QCIP)) {
		cip[0] = '\n';
		cip_nbo.s_addr = htonl(targetp->dn_cip.s_addr);
		(void) inet_ntop(AF_INET, &cip_nbo, cip + 1, INET_ADDRSTRLEN);
		(void) strlcat(cip, "|", sizeof (cip));
	}

	records = NULL;
	ent = ent0;
	for (nrecords = 0; count < 0 || nrecords < count; ent = entend + 1) {
		/*
		 * Bail if we've reached the end of the container.
		 */
		if (ent - ent0 >= st.st_size)
			break;

		/*
		 * If we're searching by client IP address, locate it
		 * quickly using strstr(3C); if we can't find it by this
		 * technique then it's not in the container.
		 */
		if (DSVC_QISEQ(query, DN_QCIP)) {
			/*
			 * If we've already found the DN_QCIP record, bail.
			 */
			if (nrecords > 0)
				break;

			ent = strstr(ent, cip);
			if (ent == NULL)
				break;
			ent++;
		}

		/*
		 * Find the end of the record and change it a NUL byte so
		 * that it is interpreted correctly with field_split() and
		 * record_match() below.  If we can't find a trailing
		 * newline, then it must be the last record (whose newline
		 * we already changed to a NUL above).
		 */
		entend = strchr(ent, '\n');
		if (entend != NULL)
			*entend = '\0';
		else
			entend = &ent0[st.st_size - 1];

		/*
		 * Skip pure comment lines; for now this just skips the
		 * header information at the top of the container.
		 */
		if (ent[0] == DNF_COMMENT_CHAR)
			continue;

		/*
		 * Split the buffer up into DNF_FIELDS fields.
		 */
		nfields = field_split(ent, DNF_FIELDS, fields, "|");
		if (nfields < DNF_FIELDS)
			continue;

		/*
		 * See if we've got a match, filling in dnf.dnf_rec as
		 * we go.  If record_match() succeeds, dnf.dnf_rec will
		 * be completely filled in.
		 */
		if (!record_match(fields, &dn, targetp, query))
			continue;

		/*
		 * Caller just wants a count of the number of matching
		 * records, not the records themselves; continue.
		 */
		if (recordsp == NULL) {
			nrecords++;
			continue;
		}

		/*
		 * Allocate record; if FIND_POSITION flag is set, then
		 * we need to allocate an extended (dn_recpos_t) record.
		 */
		if (flags & FIND_POSITION)
			recordp = malloc(sizeof (dn_recpos_t));
		else
			recordp = malloc(sizeof (dn_rec_t));

		if (recordp == NULL) {
			if ((flags & FIND_PARTIAL) == 0)
				retval = DSVC_NO_MEMORY;
			break;
		}

		/*
		 * Fill in record; do a structure copy from our automatic
		 * dn.  If FIND_POSITION flag is on, pass back additional
		 * position information.
		 */
		*recordp = dn;
		if (flags & FIND_POSITION) {
			((dn_recpos_t *)recordp)->dnp_off = ent - ent0;
			((dn_recpos_t *)recordp)->dnp_size = entend - ent + 1;
		}

		/*
		 * Chuck the record on the list; up the counter.
		 */
		new_records = add_dnrec_to_list(recordp, records);
		if (new_records == NULL) {
			free(recordp);
			if ((flags & FIND_PARTIAL) == 0)
				retval = DSVC_NO_MEMORY;
			break;
		}

		records = new_records;
		nrecords++;
	}

	(void) munmap(ent0, st.st_size);

	if (retval == DSVC_SUCCESS) {
		*nrecordsp = nrecords;
		if (recordsp != NULL)
			*recordsp = records;
		return (DSVC_SUCCESS);
	}

	if (records != NULL)
		free_dnrec_list(records);

	return (retval);
}