/*
 * restrict_source - maintains dynamic "restrict source ..." entries as
 *		     peers come and go.
 */
void
restrict_source(
	sockaddr_u *	addr,
	int		farewell,	/* 0 to add, 1 to remove */
	u_long		expire		/* 0 is infinite, valid until */
	)
{
	sockaddr_u	onesmask;
	restrict_u *	res;
	int		found_specific;

	if (!restrict_source_enabled || SOCK_UNSPEC(addr) ||
	    IS_MCAST(addr) || ISREFCLOCKADR(addr))
		return;

	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));

	SET_HOSTMASK(&onesmask, AF(addr));
	if (farewell) {
		hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
			      0, 0, 0);
		DPRINTF(1, ("restrict_source: %s removed", stoa(addr)));
		return;
	}

	/*
	 * If there is a specific entry for this address, hands
	 * off, as it is condidered more specific than "restrict
	 * server ...".
	 * However, if the specific entry found is a fleeting one
	 * added by pool_xmit() before soliciting, replace it
	 * immediately regardless of the expire value to make way
	 * for the more persistent entry.
	 */
	if (IS_IPV4(addr)) {
		res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr));
		INSIST(res != NULL);
		found_specific = (SRCADR(&onesmask) == res->u.v4.mask);
	} else {
		res = match_restrict6_addr(&SOCK_ADDR6(addr),
					   SRCPORT(addr));
		INSIST(res != NULL);
		found_specific = ADDR6_EQ(&res->u.v6.mask,
					  &SOCK_ADDR6(&onesmask));
	}
	if (!expire && found_specific && res->expire) {
		found_specific = 0;
		free_res(res, IS_IPV6(addr));
	}
	if (found_specific)
		return;

	hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
		      restrict_source_mflags, restrict_source_flags,
		      expire);
	DPRINTF(1, ("restrict_source: %s host restriction added\n", 
		    stoa(addr)));
}
Example #2
0
/*
 * restrictions - return restrictions for this host
 */
u_short
restrictions(
	sockaddr_u *srcadr
	)
{
	restrict_u *match;
	struct in6_addr *pin6;
	u_short flags;

	res_calls++;
	flags = 0;
	/* IPv4 source address */
	if (IS_IPV4(srcadr)) {
		/*
		 * Ignore any packets with a multicast source address
		 * (this should be done early in the receive process,
		 * not later!)
		 */
		if (IN_CLASSD(SRCADR(srcadr)))
			return (int)RES_IGNORE;

		match = match_restrict4_addr(SRCADR(srcadr),
					     SRCPORT(srcadr));
		match->count++;
		/*
		 * res_not_found counts only use of the final default
		 * entry, not any "restrict default ntpport ...", which
		 * would be just before the final default.
		 */
		if (&restrict_def4 == match)
			res_not_found++;
		else
			res_found++;
		flags = match->flags;
	}

	/* IPv6 source address */
	if (IS_IPV6(srcadr)) {
		pin6 = PSOCK_ADDR6(srcadr);

		/*
		 * Ignore any packets with a multicast source address
		 * (this should be done early in the receive process,
		 * not later!)
		 */
		if (IN6_IS_ADDR_MULTICAST(pin6))
			return (int)RES_IGNORE;

		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
		match->count++;
		if (&restrict_def6 == match)
			res_not_found++;
		else
			res_found++;
		flags = match->flags;
	}
	return (flags);
}
Example #3
0
const char *
sockporttoa(
	const sockaddr_u *sock
	)
{
	int		saved_errno;
	const char *	atext;
	char *		buf;

	saved_errno = errno;
	atext = socktoa(sock);
	LIB_GETBUF(buf);
	snprintf(buf, LIB_BUFLENGTH,
		 (IS_IPV6(sock))
		     ? "[%s]:%hu"
		     : "%s:%hu",
		 atext, SRCPORT(sock));
	errno = saved_errno;

	return buf;
}
Example #4
0
/* Receive data from broadcast. Couldn't finish that. Need to do some digging
 * here, especially for protocol independence and IPv6 multicast */
int 
recv_bcst_data (
	SOCKET rsock,
	char *rdata,
	int rdata_len,
	sockaddr_u *sas,
	sockaddr_u *ras
	)
{
	char *buf;
	int btrue = 1;
	int recv_bytes = 0;
	int rdy_socks;
	GETSOCKNAME_SOCKLEN_TYPE ss_len;
	struct timeval timeout_tv;
	fd_set bcst_fd;
#ifdef MCAST
	struct ip_mreq mdevadr;
	TYPEOF_IP_MULTICAST_LOOP mtrue = 1;
#endif
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
	struct ipv6_mreq mdevadr6;
#endif

	setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
	if (IS_IPV4(sas)) {
		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE))
				printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n",
				       stoa(sas), SRCPORT(sas));
		}

#ifdef MCAST
		if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) {
			/* some error message regarding setting up multicast loop */
			return BROADCAST_FAILED;
		}
		mdevadr.imr_multiaddr.s_addr = NSRCADR(sas); 
		mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
		if (mdevadr.imr_multiaddr.s_addr == ~(unsigned)0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n",
				       stoa(sas), SRCPORT(sas));
			}
			return BROADCAST_FAILED;
		}
		if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas);
				printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
				free(buf);
			}
		}
#endif	/* MCAST */
	}
#ifdef ISC_PLATFORM_HAVEIPV6
	else if (IS_IPV6(sas)) {
		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE))
				printf("sntp recv_bcst_data: Couldn't bind() address.\n");
		}
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
			/* some error message regarding setting up multicast loop */
			return BROADCAST_FAILED;
		}
		memset(&mdevadr6, 0, sizeof(mdevadr6));
		mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas);
		if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas); 
				printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
				free(buf);
			}
			return BROADCAST_FAILED;
		}
		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
			       &mdevadr6, sizeof(mdevadr6)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas); 
				printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
				free(buf);
			}
		}
#endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
	}
#endif	/* ISC_PLATFORM_HAVEIPV6 */
	FD_ZERO(&bcst_fd);
	FD_SET(rsock, &bcst_fd);
	if (ENABLED_OPT(TIMEOUT)) 
		timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT));
	else 
		timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
	timeout_tv.tv_usec = 0;
	rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv);
	switch (rdy_socks) {
	case -1: 
		if (ENABLED_OPT(NORMALVERBOSE)) 
			perror("sntp recv_bcst_data: select()");
		return BROADCAST_FAILED;
		break;
	case 0:
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n", 
			       (unsigned)timeout_tv.tv_sec);
		return BROADCAST_FAILED;
		break;
	default:
		ss_len = sizeof(*ras);
		recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
		break;
	}
	if (recv_bytes == -1) {
		if (ENABLED_OPT(NORMALVERBOSE))
			perror("sntp recv_bcst_data: recvfrom:");
		recv_bytes = BROADCAST_FAILED;
	}
#ifdef MCAST
	if (IS_IPV4(sas)) 
		setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
#endif
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
	if (IS_IPV6(sas))
		setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
#endif
	return recv_bytes;
}
Example #5
0
/*
 * restrictions - return restrictions for this host
 */
int
restrictions(
	struct sockaddr_storage *srcadr,
	int at_listhead
	)
{
	struct restrictlist *rl;
	struct restrictlist *match = NULL;
	struct restrictlist6 *rl6;
	struct restrictlist6 *match6 = NULL;
	struct in6_addr hostaddr6;
	struct in6_addr hostservaddr6;
	u_int32	hostaddr;
	int	flags = 0;
	int	isntpport;

	res_calls++;
	if (srcadr->ss_family == AF_INET) {
		/*
		 * We need the host address in host order.  Also need to
		 * know whether this is from the ntp port or not.
		 */
		hostaddr = SRCADR(srcadr);
		isntpport = (SRCPORT(srcadr) == NTP_PORT);

		/*
		 * Ignore any packets with a multicast source address
		 * (this should be done early in the receive process,
		 * later!)
		 */
		if (IN_CLASSD(SRCADR(srcadr)))
			return (int)RES_IGNORE;

		/*
		 * Set match to first entry, which is default entry.
		 * Work our way down from there.
		 */
		match = restrictlist;
		for (rl = match->next; rl != NULL && rl->addr <= hostaddr;
		    rl = rl->next)
			if ((hostaddr & rl->mask) == rl->addr) {
				if ((rl->mflags & RESM_NTPONLY) &&
				    !isntpport)
					continue;
				match = rl;
			}
		match->count++;
		if (match == restrictlist)
			res_not_found++;
		else
			res_found++;
		flags = match->flags;
	}

	/* IPv6 source address */
	if (srcadr->ss_family == AF_INET6) {
		/*
		 * Need to know whether this is from the ntp port or
		 * not.
		 */
		hostaddr6 = GET_INADDR6(*srcadr);
		isntpport = (ntohs((
		    (struct sockaddr_in6 *)srcadr)->sin6_port) ==
		    NTP_PORT);

		/*
		 * Ignore any packets with a multicast source address
		 * (this should be done early in the receive process,
		 * later!)
		 */
		if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
			return (int)RES_IGNORE;

		/*
		 * Set match to first entry, which is default entry.
		 *  Work our way down from there.
		 */
		match6 = restrictlist6;
		for (rl6 = match6->next; rl6 != NULL &&
		    (memcmp(&(rl6->addr6), &hostaddr6,
		    sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
			SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
			    &rl6->mask6);
			if (memcmp(&hostservaddr6, &(rl6->addr6),
			    sizeof(hostservaddr6)) == 0) {
				if ((rl6->mflags & RESM_NTPONLY) &&
				    !isntpport)
					continue;
				match6 = rl6;
			}
		}
		match6->count++;
		if (match6 == restrictlist6)
			res_not_found++;
		else
			res_found++;
		flags = match6->flags;
	}

	/*
	 * The following implements a generalized call gap facility.
	 * Douse the RES_LIMITED bit only if the interval since the last
	 * packet is greater than res_min_interval and the average is
	 * greater thatn res_avg_interval.
	 */
	if (!at_listhead || mon_enabled == MON_OFF) {
		flags &= ~RES_LIMITED;
	} else {
		struct mon_data *md;

		/*
		 * At this poin the most recent arrival is first in the
		 * MRU list. Let the first 10 packets in for free until
		 * the average stabilizes.
		 */
		md = mon_mru_list.mru_next;
		if (md->avg_interval == 0)
			md->avg_interval = md->drop_count;
		else
			md->avg_interval += (md->drop_count -
			    md->avg_interval) / RES_AVG;
		if (md->count < 10 || (md->drop_count >
		    res_min_interval && md->avg_interval >
		    res_avg_interval))
			flags &= ~RES_LIMITED;
		md->drop_count = flags;
	}
	return (flags);
}
/*
 * restrictions - return restrictions for this host
 */
int
restrictions(
	struct sockaddr_in *srcadr
	)
{
	register struct restrictlist *rl;
	register struct restrictlist *match;
	register u_int32 hostaddr;
	register int isntpport;

	res_calls++;
	/*
	 * We need the host address in host order.  Also need to know
	 * whether this is from the ntp port or not.
	 */
	hostaddr = SRCADR(srcadr);
	isntpport = (SRCPORT(srcadr) == NTP_PORT);

	/*
	 * Ignore any packets with a multicast source address
	 * (this should be done early in the receive process, later!)
	 */
	if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)))
	    return (int)RES_IGNORE;

	/*
	 * Set match to first entry, which is default entry.  Work our
	 * way down from there.
	 */
	match = restrictlist;

	for (rl = match->next; rl != 0 && rl->addr <= hostaddr; rl = rl->next)
	    if ((hostaddr & rl->mask) == rl->addr) {
		    if ((rl->mflags & RESM_NTPONLY) && !isntpport)
			continue;
		    match = rl;
	    }

	match->count++;
	if (match == restrictlist)
	    res_not_found++;
	else
	    res_found++;
	
	/*
	 * The following implements limiting the number of clients
	 * accepted from a given network. The notion of "same network"
	 * is determined by the mask and addr fields of the restrict
	 * list entry. The monitor mechanism has to be enabled for
	 * collecting info on current clients.
	 *
	 * The policy is as follows:
	 *	- take the list of clients recorded
	 *        from the given "network" seen within the last
	 *        client_limit_period seconds
	 *      - if there are at most client_limit entries: 
	 *        --> access allowed
	 *      - otherwise sort by time first seen
	 *      - current client among the first client_limit seen
	 *        hosts?
	 *        if yes: access allowed
	 *        else:   eccess denied
	 */
	if (match->flags & RES_LIMITED) {
		int lcnt;
		struct mon_data *md, *this_client;

#ifdef DEBUG
		if (debug > 2)
		    printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n",
			   client_limit, client_limit_period,
			   (u_long)netof(hostaddr));
#endif /*DEBUG*/
		if (mon_enabled == MON_OFF) {
#ifdef DEBUG
			if (debug > 4)
			    printf("no limit - monitoring is off\n");
#endif
			return (int)(match->flags & ~RES_LIMITED);
		}

		/*
		 * How nice, MRU list provides our current client as the
		 * first entry in the list.
		 * Monitoring was verified to be active above, thus we
		 * know an entry for our client must exist, or some 
		 * brain dead set the memory limit for mon entries to ZERO!!!
		 */
		this_client = mon_mru_list.mru_next;

		for (md = mon_fifo_list.fifo_next,lcnt = 0;
		     md != &mon_fifo_list;
		     md = md->fifo_next) {
			if ((current_time - md->lasttime)
			    > client_limit_period) {
#ifdef DEBUG
				if (debug > 5)
				    printf("checking: %s: ignore: too old: %ld\n",
					   numtoa(md->rmtadr),
					   current_time - md->lasttime);
#endif
				continue;
			}
			if (md->mode == MODE_BROADCAST ||
			    md->mode == MODE_CONTROL ||
			    md->mode == MODE_PRIVATE) {
#ifdef DEBUG
				if (debug > 5)
				    printf("checking: %s: ignore mode %d\n",
					   numtoa(md->rmtadr),
					   md->mode);
#endif
				continue;
			}
			if (netof(md->rmtadr) !=
			    netof(hostaddr)) {
#ifdef DEBUG
				if (debug > 5)
				    printf("checking: %s: different net 0x%lX\n",
					   numtoa(md->rmtadr),
					   (u_long)netof(md->rmtadr));
#endif
				continue;
			}
			lcnt++;
			if (lcnt >  (int) client_limit ||
			    md->rmtadr == hostaddr) {
#ifdef DEBUG
				if (debug > 5)
				    printf("considering %s: found host\n",
					   numtoa(md->rmtadr));
#endif
				break;
			}
#ifdef DEBUG
			else {
				if (debug > 5)
				    printf("considering %s: same net\n",
					   numtoa(md->rmtadr));
			}
#endif

		}
#ifdef DEBUG
		if (debug > 4)
		    printf("this one is rank %d in list, limit is %lu: %s\n",
			   lcnt, client_limit,
			   (lcnt <= (int) client_limit) ? "ALLOW" : "REJECT");
#endif
		if (lcnt <= (int) client_limit) {
			this_client->lastdrop = 0;
			return (int)(match->flags & ~RES_LIMITED);
		} else {
			this_client->lastdrop = current_time;
		}
	}
	return (int)match->flags;
}
Example #7
0
/*
 * restrictions - return restrictions for this host in *r4a
 */
void
restrictions(
	sockaddr_u *srcadr,
	r4addr *r4a
	)
{
	restrict_u *match;
	struct in6_addr *pin6;

	REQUIRE(NULL != r4a);

	res_calls++;
	r4a->rflags = RES_IGNORE;
	r4a->ippeerlimit = 0;

	DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr)));

	/* IPv4 source address */
	if (IS_IPV4(srcadr)) {
		/*
		 * Ignore any packets with a multicast source address
		 * (this should be done early in the receive process,
		 * not later!)
		 */
		if (IN_CLASSD(SRCADR(srcadr))) {
			DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr)));
			r4a->ippeerlimit = 2;	/* XXX: we should use a better value */
			return;
		}

		match = match_restrict4_addr(SRCADR(srcadr),
					     SRCPORT(srcadr));

		INSIST(match != NULL);

		match->count++;
		/*
		 * res_not_found counts only use of the final default
		 * entry, not any "restrict default ntpport ...", which
		 * would be just before the final default.
		 */
		if (&restrict_def4 == match)
			res_not_found++;
		else
			res_found++;
		r4a->rflags = match->rflags;
		r4a->ippeerlimit = match->ippeerlimit;
	}

	/* IPv6 source address */
	if (IS_IPV6(srcadr)) {
		pin6 = PSOCK_ADDR6(srcadr);

		/*
		 * Ignore any packets with a multicast source address
		 * (this should be done early in the receive process,
		 * not later!)
		 */
		if (IN6_IS_ADDR_MULTICAST(pin6))
			return;

		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
		INSIST(match != NULL);
		match->count++;
		if (&restrict_def6 == match)
			res_not_found++;
		else
			res_found++;
		r4a->rflags = match->rflags;
		r4a->ippeerlimit = match->ippeerlimit;
	}
	return;
}
Example #8
0
/*
 *	Write captured packet to file
 *
 *	uint8_t *flag : filter is set or not
 *	const uint8_t *packet : captured packet
 *	char *fltrload : filter for payload
 *	cosnt int payloadlen : length of captured payload
 */
static void printfile(uint8_t *flag, const uint8_t *packet, char *fltrload, const int payloadlen)
{
	FILE *fp = fopen(LOGFILE, "a");
	const uint8_t *http = NULL;
	char *timestamp;
	struct ether_header *eth;
	struct ip *iphdr;
	struct tcphdr *tcphdr;
	struct udphdr *udphdr;
	uint8_t prot;
	int hdrlen, i;

	flag += 2;  // remove unused member

	eth = (struct ether_header *)packet;
	hdrlen = sizeof(struct ether_header);

	iphdr = (struct ip *)(packet + hdrlen);
	hdrlen += sizeof(struct ip);

	prot = iphdr->ip_p;
	if( prot == 17 ) {
		udphdr = (struct udphdr *)(packet + hdrlen);
		hdrlen += sizeof(struct udphdr);
	}else {
		tcphdr = (struct tcphdr *)(packet + hdrlen);
		hdrlen += sizeof(struct tcphdr);

		// HTTP request check 
		if( PROTOCOL(flag) ) {
			if( prot == 3 ) {
				if( HTTPTEST("GET",3) == false )
					return;

			}else if( prot == 5 ) {
				if( HTTPTEST("PUT",3) == false )
					return;

			}else if(prot == 7) {
				if( HTTPTEST("POST",4) == false )
					return;
			}
		}
	}

	
	

	// Timestamp
	timestamp = (char *)gettime();
	fprintf(fp, "%s ------\n", timestamp);
	free(timestamp);

	/* Ethernet Header */
	i = 0;
	if( DSTMAC(flag) ) {
		fprintf(fp, "\x1b[45mDestination MAC\x1b[0m\t: \x1b[45m");
		while( i < 5 )
			fprintf(fp, "%02X:", eth->ether_dhost[i++]);
		fprintf(fp, "%02X\x1b[0m\n", eth->ether_dhost[i]);
	}else {
		fprintf(fp, "Destination MAC\t: ");
		while( i < 5 )
			fprintf(fp, "%02X:", eth->ether_dhost[i++]);
		fprintf(fp, "%02X\n", eth->ether_dhost[i]);
	}

	i = 0;
	if( SRCMAC(flag) ) {
		fprintf(fp, "\x1b[45mSource MAC\x1b[0m\t: \x1b[45m");
		while( i < 5 )
			fprintf(fp, "%02X:", eth->ether_shost[i++]);
		fprintf(fp, "%02X\x1b[0m\n", eth->ether_shost[i]);
	}else {
		fprintf(fp, "Source MAC\t: ");
		while( i < 5 )
			fprintf(fp, "%02X:", eth->ether_shost[i++]);
		fprintf(fp, "%02X\n", eth->ether_shost[i]);
	}

	if( ETHERTYPE(flag) )
		fprintf(fp, "\x1b[45mEthernet Type\x1b[0m\t: \x1b[45m%s\x1b[0m\n", gettype(eth->ether_type));
	else
		fprintf(fp, "Ethernet Type\t: %s\n", gettype(eth->ether_type));

	/* IP Header */
	if( VERSION(flag) & 0xf0 )
		fprintf(fp, "\x1b[44mVersion\x1b[0m\t\t: \x1b[44m%d\x1b[0m\n", iphdr->ip_v);
	else
		fprintf(fp, "Version\t\t: %d\n", iphdr->ip_v);

	if( IPHLEN(flag) & 0x0f )
		fprintf(fp, "\x1b[44mIP Header length\x1b[0m: \x1b[44m%d\x1b[0m\n", iphdr->ip_hl);
	else
		fprintf(fp, "IP Header length: %d\n", iphdr->ip_hl);

	if( TOS(flag) )
		fprintf(fp, "\x1b[44mType of Service\x1b[0m\t: \x1b[44m%s\x1b[0m\n", gettos(iphdr->ip_tos));
	else
		fprintf(fp, "Type of Service\t: %s\n", gettos(iphdr->ip_tos));

	if( IPLEN(flag) )
		fprintf(fp, "\x1b[44mTotal length\x1b[0m\t: \x1b[44m%d\x1b[0m\n", ntohs(iphdr->ip_len));
	else
		fprintf(fp, "Total length\t: %d\n", ntohs(iphdr->ip_len));

	if( IPID(flag) )
		fprintf(fp, "\x1b[44mIdentification\x1b[0m\t: \x1b[44m%d\x1b[0m\n", ntohs(iphdr->ip_id));
	else
		fprintf(fp, "Identification\t: %d\n", ntohs(iphdr->ip_id));

	if( FRAGMENT(flag) )
		fprintf(fp, "\x1b[44mFragment\x1b[0m\t: \x1b[44m%d\x1b[0m\n", iphdr->ip_off);
	else
		fprintf(fp, "Fragment\t: %d\n", iphdr->ip_off);

	if( TTL(flag) )
		fprintf(fp, "\x1b[44mTime to live\x1b[0m\t: \x1b[44m%d\x1b[0m\n", iphdr->ip_ttl);
	else
		fprintf(fp, "Time to live\t: %d\n", iphdr->ip_ttl);

	if( PROTOCOL(flag) )
		fprintf(fp, "\x1b[44mProtocol\x1b[0m\t: \x1b[44m%s\x1b[0m\n", getprot(iphdr->ip_p));
	else
		fprintf(fp, "Protocol\t: %s\n", getprot(iphdr->ip_p));

	if( IPCKSUM(flag) )
		fprintf(fp, "\x1b[44mChecksum\x1b[0m\t: \x1b[44m%d\x1b[0m\n", ntohs(iphdr->ip_sum));
	else
		fprintf(fp, "Checksum\t: %d\n", ntohs(iphdr->ip_sum));

	if( SRCIP(flag) )
		fprintf(fp, "\x1b[44mSource IP\x1b[0m\t: \x1b[44m%s\x1b[0m\n", inet_ntoa(iphdr->ip_src));
	else
		fprintf(fp, "Source IP\t: %s\n", inet_ntoa(iphdr->ip_src));

	if( DSTIP(flag) )
		fprintf(fp, "\x1b[44mDestination IP\x1b[0m\t: \x1b[44m%s\x1b[0m\n", inet_ntoa(iphdr->ip_dst));
	else
		fprintf(fp, "Destination IP\t: %s\n", inet_ntoa(iphdr->ip_dst));

	if( iphdr->ip_p == 17 ) {
	/* UDP Header */
		if( SRCPORT(flag) )
			fprintf(fp, "\x1b[42mSource Port\x1b[0m\t: \x1b[42m%d\x1b[0m\n", ntohs(udphdr->source));
		else
			fprintf(fp, "Source Port\t: %d\n", ntohs(udphdr->source));

		if( DSTPORT(flag) )
			fprintf(fp, "\x1b[42mDestination Port\x1b[0m: \x1b[42m%d\x1b[0m\n", ntohs(udphdr->dest));
		else
			fprintf(fp, "Destination Port: %d\n", ntohs(udphdr->dest));

		if( UDPLEN(flag) )
			fprintf(fp, "\x1b[42mTotal length\x1b[0m\t: \x1b[42m%d\x1b[0m\n", ntohs(udphdr->len));
		else
			fprintf(fp, "Total length\t: %d\n", ntohs(udphdr->len));

		if( UDPCKSUM(flag) )
			fprintf(fp, "\x1b[42mCheckSum\x1b[0m\t: \x1b[42m%d\x1b[0m\n", ntohs(udphdr->check));
		else
			fprintf(fp, "Checksum\t: %d\n", ntohs(udphdr->check));
	}else {
	/* TCP Header */
		if( SRCPORT(flag) )
			fprintf(fp, "\x1b[31;43mSource Port\x1b[0m\t: \x1b[31;43m%d\x1b[0m\n", ntohs(tcphdr->source));
		else
			fprintf(fp, "Source Port\t: %d\n", ntohs(tcphdr->source));

		if( DSTPORT(flag) )
			fprintf(fp, "\x1b[31;43mDestination Port\x1b[0m: \x1b[31;43m%d\x1b[0m\n", ntohs(tcphdr->dest));
		else
			fprintf(fp, "Destination Port: %d\n", ntohs(tcphdr->dest));

		if( SEQ(flag) )
			fprintf(fp, "\x1b[31;43mSequence Number\x1b[0m\t: \x1b[31;43m%u\x1b[0m\n", ntohl(tcphdr->seq));
		else
			fprintf(fp, "Sequence Number\t: %u\n", ntohl(tcphdr->seq));

		if( ACK(flag) )
			fprintf(fp, "\x1b[31;43mAcknowledgement\x1b[0m\t: \x1b[31;43m%u\x1b[0m\n", ntohl(tcphdr->ack));
		else
			fprintf(fp, "Acknowledgement\t: %u\n", ntohl(tcphdr->ack));

		if( TCPOFF(flag) & 0x0f )
			fprintf(fp, "\x1b[31;43mOffset\x1b[0m\t\t: \x1b[31;43m%d\x1b[0m\n", tcphdr->doff);
		else
			fprintf(fp, "Offset\t\t: %d\n", tcphdr->doff);

		if( TCPRES(flag) & 0xf0 )
			fprintf(fp, "\x1b[31;43mReserved\x1b[0m\t: \x1b[31;43m%d\x1b[0m\n", tcphdr->res1);
		else
			fprintf(fp, "Reserved\t: %d\n", tcphdr->res1);

		char *tmp = getflag(*(packet + 47), tcphdr->res1, tcphdr->res2);
		if( TCPFLAG(flag) )
			fprintf(fp, "\x1b[31;43mFlags\x1b[0m\t\t: \x1b[31;43m%s\x1b[0m\n", tmp);
		else
			fprintf(fp, "Flags\t\t: %s\n", tmp);
		free(tmp);

		if( WINDOW(flag) )
			fprintf(fp, "\x1b[31;43mWindow size\x1b[0m\t: \x1b[31;43m%d\x1b[0m\n", ntohs(tcphdr->window));
		else
			fprintf(fp, "Window size\t: %d\n", ntohs(tcphdr->window));

		if( TCPCKSUM(flag) )
			fprintf(fp, "\x1b[31;43mChecksum\x1b[0m\t: \x1b[31;43m%d\x1b[0m\n", ntohs(tcphdr->check));
		else
			fprintf(fp, "Checksum\t: %d\n", ntohs(tcphdr->check));

		if( URGPTR(flag) )
			fprintf(fp, "\x1b[31;43mUrgent Pointer\x1b[0m\t: \x1b[31;43m%d\x1b[0m\n", ntohs(tcphdr->urg_ptr));
		else
			fprintf(fp, "Urgent Pointer\t: %d\n", ntohs(tcphdr->urg_ptr));
	}

	/* Payload */
	if( fltrload != NULL ) {
		const uint8_t *match = NULL;
		uint8_t highlight[MAXPAYLOAD];
		int fltrloadlen, unmatchlen = 0;
		int colorhex = 0, colorstr = 0;
		int i = 0, str = 0, colorlen = 0, highlen = 0;
		char ch;

		memset(highlight, 0, MAXPAYLOAD);

		packet += hdrlen;
		fltrloadlen = strlen(fltrload);

		fprintf(fp, "*** Payload ***\n");

		if( http != NULL ) {
			if( prot == 3 ) {
				memcpy(highlight, HTTPCOLOR, 5);
				memcpy(highlight + 5, "GET\x1b[0m", 7);
				highlen += 12;
				i += 3;

			}else if( prot == 5 ) {
				memcpy(highlight, HTTPCOLOR, 5);
				memcpy(highlight + 5, "PUT\x1b[0m", 7);
				highlen += 12;
				i += 3;

			}else if( prot == 7 ) {
				memcpy(highlight, HTTPCOLOR, 5);
				memcpy(highlight + 5, "POST\x1b[0m", 8);
				highlen += 13;
				i += 4;
			}
		}

		while( i < payloadlen ) {
			// move to next matching string
			match = memcmp_cont(packet + i, fltrload, fltrloadlen, payloadlen - i);
			if( match == NULL ) {
				unmatchlen = payloadlen - i;

				memcpy(highlight + highlen, packet + i, unmatchlen);
				highlen += unmatchlen;

				break;
			}else {

				if( http != NULL && match - packet > http - packet ) {
				// HTTP/1.1
					unmatchlen = http - (packet + i);

					memcpy(highlight + highlen, packet + i, unmatchlen);
					highlen += unmatchlen;
					i += unmatchlen;

					memcpy(highlight + highlen, "\x1b[46mHTTP/1.1\x1b[0m", 17);
					highlen += 17;
					i += 8;
					http = NULL;
				}else {
					unmatchlen = match - (packet + i);

					memcpy(highlight + highlen, packet + i, unmatchlen);
					highlen += unmatchlen;
					i += unmatchlen;

					memcpy(highlight + highlen, PAYLOADCOLOR, 5);
					highlen += 5;

					memcpy(highlight + highlen, packet + i, fltrloadlen);
					highlen += fltrloadlen;
					i += fltrloadlen;

					memcpy(highlight + highlen, NORMALCOLOR, 4);
					highlen += 4;
				}
			}
		}

		i = 0;
		while( i < highlen ) {
			ch = *(highlight + i);

			if( ch == '\x1b' ) {
				if( COLORTEST(i, PAYLOADCOLOR) == true ) {
					fprintf(fp, PAYLOADCOLOR);
					colorhex = 41;
					i += 5;
					colorlen += 5;
					continue;

				}else if( COLORTEST(i, HTTPCOLOR) == true ) {
					fprintf(fp, HTTPCOLOR);
					colorhex = 46;
					i += 5;
					colorlen += 5;
					continue;

				}else if( COLORTEST(i, NORMALCOLOR) == true ) {
					fprintf(fp, NORMALCOLOR);
					colorhex = 0;
					i += 4;
					colorlen += 4;
					continue;
				}
			}

			fprintf(fp, "%02X ", ch);
			i++;

			if( ++str == 16 ) {
				if( colorhex != 0 )
					fprintf(fp, NORMALCOLOR);

				fprintf(fp, "   ");

				if( colorstr == 41 ) {
					fprintf(fp, PAYLOADCOLOR);
					colorstr = 0;

				}else if( colorstr == 46 ) {
					fprintf(fp, HTTPCOLOR);
					colorstr = 0;
				}

				while( colorlen > 0 ) {
					ch = *(highlight + i - colorlen - str);
					if( ch > 126 || ch < 32 ) {
						if( ch == 27 ) {
							if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
								colorstr = 41;

							else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
								colorstr = 46;

							else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
								colorstr = 0;

							else
								ch = '.';
						}else
							ch = '.';
					}
					fprintf(fp, "%c", ch);
					colorlen--;
				}

				while( str > 0 ) {
					ch = *(highlight + i - str);
					if( ch > 126 || ch < 32 ) {
						if( ch == 27 ) {
							if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
								colorstr = 41;
							else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
								colorstr = 46;
							else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
								colorstr = 0;
							else
								ch = '.';
						}else
							ch = '.';
					}
					fprintf(fp, "%c", ch);
					str--;
				}

				if( colorstr != 0 )
					fprintf(fp, NORMALCOLOR);

				fprintf(fp, "\n");

				if( colorhex == 41 ) {
					fprintf(fp, PAYLOADCOLOR);
					colorhex = 0;

				}else if( colorhex == 46 ) {
					fprintf(fp, HTTPCOLOR);
					colorhex = 0;
				}
			}
		}

		if( str != 0 ) {
			int padd = 17;
			if( colorhex != 0 )
				fprintf(fp, NORMALCOLOR);

			while( str < padd-- )
				fprintf(fp, "   ");

			if( colorstr == 41 ) {
				fprintf(fp, PAYLOADCOLOR);
				colorstr = 0;

			}else if( colorstr == 46 ) {
				fprintf(fp, HTTPCOLOR);
				colorstr = 0;
			}

			while( colorlen > 0 ) {
				ch = *(highlight + i - colorlen - str);
				if( ch > 126 || ch < 32 ) {
					if( ch == 27 ) {
						if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
							colorstr = 41;
						else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
							colorstr = 46;
						else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
							colorstr = 0;
						else
							ch = '.';
					}else
						ch = '.';
				}
				fprintf(fp, "%c", ch);
				colorlen--;
			}

			while( str > 0 ) {
				ch = *(highlight + i - str);
				if( ch > 126 || ch < 32 ) {
					if( ch == 27 ) {
						if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
							colorstr = 41;
						else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
							colorstr = 46;
						else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
							colorstr = 0;
						else
							ch = '.';
					}else
						ch = '.';
				}
				fprintf(fp, "%c", ch);
				str--;
			}
			fprintf(fp, "\x1b[0m\n");
		}
	}else { // fltrload == NULL
		uint8_t highlight[MAXPAYLOAD];
		int unmatchlen = 0;
		int colorhex = 0, colorstr = 0;
		int i = 0, str = 0, colorlen = 0, highlen = 0;
		char ch;

		memset(highlight, 0, MAXPAYLOAD);

		packet += hdrlen;

		fprintf(fp, "*** Payload ***\n");

		if( http != NULL ) {
			if( prot == 3 ) {
				memcpy(highlight, HTTPCOLOR, 5);
				memcpy(highlight + 5, "GET\x1b[0m", 7);
				highlen += 12;
				i += 3;

			}else if( prot == 5 ) {
				memcpy(highlight, HTTPCOLOR, 5);
				memcpy(highlight + 5, "PUT\x1b[0m", 7);
				highlen += 12;
				i += 3;

			}else if( prot == 7 ) {
				memcpy(highlight, HTTPCOLOR, 5);
				memcpy(highlight + 5, "POST\x1b[0m", 8);
				highlen += 13;
				i += 4;
			}
		}

		while( i < payloadlen ) {
		// move to next matching string
			if( http != NULL ) {
			// HTTP/1.1
				unmatchlen = http - (packet + i);

				memcpy(highlight + highlen, packet + i, unmatchlen);
				highlen += unmatchlen;
				i += unmatchlen;

				memcpy(highlight + highlen, "\x1b[46mHTTP/1.1\x1b[0m", 17);
				highlen += 17;
				i += 8;
				http = NULL;
			}else {
				memcpy(highlight + highlen, packet + i, payloadlen - i);
				highlen += unmatchlen;
				i += unmatchlen;
			}
		}

		i = 0;
		while( i < highlen ) {
			ch = *(highlight + i);

			if( ch == '\x1b' ) {
				if( COLORTEST(i, PAYLOADCOLOR) == true ) {
					fprintf(fp, PAYLOADCOLOR);
					colorhex = 41;
					i += 5;
					colorlen += 5;
					continue;

				}else if( COLORTEST(i, HTTPCOLOR) == true ) {
					fprintf(fp, HTTPCOLOR);
					colorhex = 46;
					i += 5;
					colorlen += 5;
					continue;

				}else if( COLORTEST(i, NORMALCOLOR) == true ) {
					fprintf(fp, NORMALCOLOR);
					colorhex = 0;
					i += 4;
					colorlen += 4;
					continue;
				}
			}

			fprintf(fp, "%02X ", ch);
			i++;

			if( ++str == 16 ) {
				if( colorhex != 0 )
					fprintf(fp, NORMALCOLOR);

				fprintf(fp, "   ");

				if( colorstr == 41 ) {
					fprintf(fp, PAYLOADCOLOR);
					colorstr = 0;

				}else if( colorstr == 46 ) {
					fprintf(fp, HTTPCOLOR);
					colorstr = 0;
				}

				while( colorlen > 0 ) {
					ch = *(highlight + i - colorlen - str);
					if( ch > 126 || ch < 32 ) {
						if( ch == 27 ) {
							if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
								colorstr = 41;
							else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
								colorstr = 46;
							else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
								colorstr = 0;
							else
								ch = '.';
						}else
							ch = '.';
					}
					fprintf(fp, "%c", ch);
					colorlen--;
				}

				while( str > 0 ) {
					ch = *(highlight + i - str);
					if( ch > 126 || ch < 32 ) {
						if( ch == 27 ) {
							if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
								colorstr = 41;
							else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
								colorstr = 46;
							else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
								colorstr = 0;
							else
								ch = '.';
						}else
							ch = '.';
					}
					fprintf(fp, "%c", ch);
					str--;
				}

				if( colorstr != 0 )
					fprintf(fp, NORMALCOLOR);

				fprintf(fp, "\n");

				if( colorhex == 41 ) {
					fprintf(fp, PAYLOADCOLOR);
					colorhex = 0;

				}else if( colorhex == 46 ) {
					fprintf(fp, HTTPCOLOR);
					colorhex = 0;
				}
			}
		}

		if( str != 0 ) {
			int padd = 17;
			if( colorhex != 0 )
				fprintf(fp, NORMALCOLOR);

			while( str < padd-- )
				fprintf(fp, "   ");

			if( colorstr == 41 ) {
				fprintf(fp, PAYLOADCOLOR);
				colorstr = 0;

			}else if( colorstr == 46 ) {
				fprintf(fp, HTTPCOLOR);
				colorstr = 0;
			}

			while( colorlen > 0 ) {
				ch = *(highlight + i - colorlen - str);
				if( ch > 126 || ch < 32 ) {
					if( ch == 27 ) {
						if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
							colorstr = 41;
						else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
							colorstr = 46;
						else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
							colorstr = 0;
						else
							ch = '.';
					}else
						ch = '.';
				}
				fprintf(fp, "%c", ch);
				colorlen--;
			}

			while( str > 0 ) {
				ch = *(highlight + i - str);
				if( ch > 126 || ch < 32 ) {
					if( ch == 27 ) {
						if( COLORTEST(i - colorlen - str, PAYLOADCOLOR) == true )
							colorstr = 41;
						else if( COLORTEST(i - colorlen - str, HTTPCOLOR) == true )
							colorstr = 46;
						else if( COLORTEST(i - colorlen - str, NORMALCOLOR) == true )
							colorstr = 0;
						else
							ch = '.';
					}else
						ch = '.';
				}
				fprintf(fp, "%c", ch);
				str--;
			}
			fprintf(fp, "\x1b[0m\n");
		}
	}
	fprintf(fp, "----------------------------\n");
	fclose(fp);
}