Esempio n. 1
0
			/* Add the value, subtract its position */
			*location += sym->st_value - (uint32_t)location;
			break;
		default:
			pr_err("%s: Unknown relocation: %u\n",
			       me->name, ELF32_R_TYPE(rel[i].r_info));
			return -ENOEXEC;
		}
	}
	return 0;
}
#else /*X86_64*/
int apply_relocate_add(Elf64_Shdr *sechdrs,
		   const char *strtab,
		   unsigned int symindex,
		   unsigned int relsec,
		   struct module *me)
{
	unsigned int i;
	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
	Elf64_Sym *sym;
	void *loc;
	u64 val;
	bool rhel70 = check_module_rhelversion(me, "7.0");
	bool warned = false;

	DEBUGP("Applying relocate section %u to %u\n",
	       relsec, sechdrs[relsec].sh_info);

	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
		Elf64_Sym kstack_sym;
		bool apply_kstack_fixup = false;
		const char *symname;

		/* This is where to make the change */
		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
			+ rel[i].r_offset;

		/* This is the symbol it is referring to.  Note that all
		   undefined symbols have been resolved.  */
		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
			+ ELF64_R_SYM(rel[i].r_info);
		symname = strtab + sym->st_name;

		DEBUGP("symname %s type %d st_value %Lx r_addend %Lx loc %Lx\n",
		       symname, (int)ELF64_R_TYPE(rel[i].r_info),
		       sym->st_value, rel[i].r_addend, (u64)loc);

		if (rhel70 && !strcmp(symname, "kernel_stack")) {
			if (!warned)
				printk(KERN_INFO "%s: applying kernel_stack fix up\n",
					me->name);
			apply_kstack_fixup = true;
			warned = true;
		}

		/* kernel_stack is referenced to access current_thread_info in
		 * a variety of places... if we're loading a module which
		 * expects an 8K stack, fix up the symbol reference to look
		 * at a second copy. Nobody should be using this symbol for
		 * any other purpose.
		 */
		if (apply_kstack_fixup) {
			const struct kernel_symbol *ksym2;
			ksym2 = find_symbol("__kernel_stack_70__",
					    NULL, NULL, true, true);
			if (!IS_ERR(ksym2)) {
				kstack_sym.st_value = ksym2->value;
				sym = &kstack_sym;
			} else
				return PTR_ERR(ksym2) ?: -ENOEXEC;
		}

		val = sym->st_value + rel[i].r_addend;

		switch (ELF64_R_TYPE(rel[i].r_info)) {
		case R_X86_64_NONE:
			break;
		case R_X86_64_64:
			*(u64 *)loc = val;
			break;
		case R_X86_64_32:
			*(u32 *)loc = val;
			if (val != *(u32 *)loc)
				goto overflow;
			break;
		case R_X86_64_32S:
			*(s32 *)loc = val;
			if ((s64)val != *(s32 *)loc)
				goto overflow;
			break;
		case R_X86_64_PC32:
			val -= (u64)loc;
			*(u32 *)loc = val;
#if 0
			if ((s64)val != *(s32 *)loc)
				goto overflow;
#endif
			break;
		default:
			pr_err("%s: Unknown rela relocation: %llu\n",
			       me->name, ELF64_R_TYPE(rel[i].r_info));
			return -ENOEXEC;
		}
	}
	return 0;

overflow:
	pr_err("overflow in relocation type %d val %Lx\n",
	       (int)ELF64_R_TYPE(rel[i].r_info), val);
	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
	       me->name);
	return -ENOEXEC;
}
static int pptp_expectfn(struct ip_conntrack *ct)
{
	struct ip_conntrack *master;
	struct ip_conntrack_expect *exp;

	DEBUGP("increasing timeouts\n");
	/* increase timeout of GRE data channel conntrack entry */
	ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;

	master = master_ct(ct);
	if (!master) {
		DEBUGP(" no master!!!\n");
		return 0;
	}

	exp = ct->master;
	if (!exp) {
		DEBUGP("no expectation!!\n");
		return 0;
	}

	DEBUGP("completing tuples with ct info\n");
	/* we can do this, since we're unconfirmed */
	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
		htonl(master->help.ct_pptp_info.pac_call_id)) {	
		/* assume PNS->PAC */
		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
			htonl(master->help.ct_pptp_info.pns_call_id);
		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
			htonl(master->help.ct_pptp_info.pns_call_id);
	} else {
		/* assume PAC->PNS */
		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
			htonl(master->help.ct_pptp_info.pac_call_id);
		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
			htonl(master->help.ct_pptp_info.pac_call_id);
	}
	
	/* delete other expectation */
	if (exp->expected_list.next != &exp->expected_list) {
		struct ip_conntrack_expect *other_exp;
		struct list_head *cur_item, *next;

		for (cur_item = master->sibling_list.next;
		     cur_item != &master->sibling_list; cur_item = next) {
			next = cur_item->next;
			other_exp = list_entry(cur_item,
					       struct ip_conntrack_expect,
					       expected_list);
			/* remove only if occurred at same sequence number */
			if (other_exp != exp && other_exp->seq == exp->seq) {
				DEBUGP("unexpecting other direction\n");
				ip_ct_gre_keymap_destroy(other_exp);
				ip_conntrack_unexpect_related(other_exp);
			}
		}
	}

	return 0;
}
Esempio n. 3
0
int apply_relocate_add(Elf64_Shdr *sechdrs,
		   const char *strtab,
		   unsigned int symindex,
		   unsigned int relsec,
		   struct module *me)
{
	unsigned int i;
	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
	Elf64_Sym *sym;
	void *loc;
	u64 val;

#ifdef CONFIG_PAX_KERNEXEC
	unsigned long cr0;
#endif

	DEBUGP("Applying relocate section %u to %u\n", relsec,
	       sechdrs[relsec].sh_info);
	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
		/* This is where to make the change */
		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
			+ rel[i].r_offset;

		/* This is the symbol it is referring to.  Note that all
		   undefined symbols have been resolved.  */
		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
			+ ELF64_R_SYM(rel[i].r_info);

	        DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
		       (int)ELF64_R_TYPE(rel[i].r_info), 
		       sym->st_value, rel[i].r_addend, (u64)loc);

		val = sym->st_value + rel[i].r_addend; 

		switch (ELF64_R_TYPE(rel[i].r_info)) {
		case R_X86_64_NONE:
			break;
		case R_X86_64_64:

#ifdef CONFIG_PAX_KERNEXEC
			pax_open_kernel(cr0);
#endif

			*(u64 *)loc = val;

#ifdef CONFIG_PAX_KERNEXEC
			pax_close_kernel(cr0);
#endif

			break;
		case R_X86_64_32:

#ifdef CONFIG_PAX_KERNEXEC
			pax_open_kernel(cr0);
#endif

			*(u32 *)loc = val;

#ifdef CONFIG_PAX_KERNEXEC
			pax_close_kernel(cr0);
#endif

			if (val != *(u32 *)loc)
				goto overflow;
			break;
		case R_X86_64_32S:

#ifdef CONFIG_PAX_KERNEXEC
			pax_open_kernel(cr0);
#endif

			*(s32 *)loc = val;

#ifdef CONFIG_PAX_KERNEXEC
			pax_close_kernel(cr0);
#endif

			if ((s64)val != *(s32 *)loc)
				goto overflow;
			break;
		case R_X86_64_PC32: 
			val -= (u64)loc;

#ifdef CONFIG_PAX_KERNEXEC
			pax_open_kernel(cr0);
#endif

			*(u32 *)loc = val;

#ifdef CONFIG_PAX_KERNEXEC
			pax_close_kernel(cr0);
#endif

#if 0
			if ((s64)val != *(s32 *)loc)
				goto overflow; 
#endif
			break;
		default:
			printk(KERN_ERR "module %s: Unknown rela relocation: %Lu\n",
			       me->name, ELF64_R_TYPE(rel[i].r_info));
			return -ENOEXEC;
		}
	}
	return 0;

overflow:
	printk(KERN_ERR "overflow in relocation type %d val %Lx\n", 
	       (int)ELF64_R_TYPE(rel[i].r_info), val);
	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
	       me->name);
	return -ENOEXEC;
}
/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
static inline int
exp_gre(struct ip_conntrack *master,
	u_int32_t seq,
	u_int16_t callid,
	u_int16_t peer_callid)
{
	struct ip_conntrack_expect exp;
	struct ip_conntrack_tuple inv_tuple;

	memset(&exp, 0, sizeof(exp));
	/* tuple in original direction, PNS->PAC */
	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
	exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
	exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
	exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
	exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
	exp.tuple.dst.protonum = IPPROTO_GRE;

	exp.mask.src.ip = 0xffffffff;
	exp.mask.src.u.all = 0;
	exp.mask.dst.u.all = 0;
	exp.mask.dst.u.gre.key = 0xffffffff;
	exp.mask.dst.u.gre.version = 0xff;
	exp.mask.dst.u.gre.protocol = 0xffff;
	exp.mask.dst.ip = 0xffffffff;
	exp.mask.dst.protonum = 0xffff;
			
	exp.seq = seq;
	exp.expectfn = pptp_expectfn;

	exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
	exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);

	DEBUGP("calling expect_related ");
	DUMP_TUPLE_RAW(&exp.tuple);
	
	/* Add GRE keymap entries */
	if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
		return 1;

	invert_tuplepr(&inv_tuple, &exp.tuple);
	if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
		ip_ct_gre_keymap_destroy(&exp);
		return 1;
	}
	
	if (ip_conntrack_expect_related(master, &exp) != 0) {
		ip_ct_gre_keymap_destroy(&exp);
		DEBUGP("cannot expect_related()\n");
		return 1;
	}

	/* tuple in reply direction, PAC->PNS */
	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
	exp.tuple.src.u.gre.key = htonl(ntohs(callid));
	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
	exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));

	DEBUGP("calling expect_related ");
	DUMP_TUPLE_RAW(&exp.tuple);
	
	/* Add GRE keymap entries */
	ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
	invert_tuplepr(&inv_tuple, &exp.tuple);
	ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
	/* FIXME: cannot handle error correctly, since we need to free
	 * the above keymap :( */
	
	if (ip_conntrack_expect_related(master, &exp) != 0) {
		/* free the second pair of keypmaps */
		ip_ct_gre_keymap_destroy(&exp);
		DEBUGP("cannot expect_related():\n");
		return 1;
	}

	return 0;
}
static inline int
pptp_outbound_pkt(struct tcphdr *tcph,
		  struct pptp_pkt_hdr *pptph,
		  size_t datalen,
		  struct ip_conntrack *ct,
		  enum ip_conntrack_info ctinfo)
{
	struct PptpControlHeader *ctlh;
        union pptp_ctrl_union pptpReq;
	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
	u_int16_t msg, *cid, *pcid;

	ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
	pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));

	msg = ntohs(ctlh->messageType);
	DEBUGP("outbound control message %s\n", strMName[msg]);

	switch (msg) {
	case PPTP_START_SESSION_REQUEST:
		/* client requests for new control session */
		if (info->sstate != PPTP_SESSION_NONE) {
			DEBUGP("%s but we already have one",
				strMName[msg]);
		}
		info->sstate = PPTP_SESSION_REQUESTED;
		break;
	case PPTP_STOP_SESSION_REQUEST:
		/* client requests end of control session */
		info->sstate = PPTP_SESSION_STOPREQ;
		break;

	case PPTP_OUT_CALL_REQUEST:
		/* client initiating connection to server */
		if (info->sstate != PPTP_SESSION_CONFIRMED) {
			DEBUGP("%s but no session\n",
				strMName[msg]);
			break;
		}
		info->cstate = PPTP_CALL_OUT_REQ;
		/* track PNS call id */
		cid = &pptpReq.ocreq->callID;
		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
		info->pns_call_id = ntohs(*cid);
		break;
	case PPTP_IN_CALL_REPLY:
		/* client answers incoming call */
		if (info->cstate != PPTP_CALL_IN_REQ
		    && info->cstate != PPTP_CALL_IN_REP) {
			DEBUGP("%s without incall_req\n", 
				strMName[msg]);
			break;
		}
		if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
			info->cstate = PPTP_CALL_NONE;
			break;
		}
		pcid = &pptpReq.icack->peersCallID;
		if (info->pac_call_id != ntohs(*pcid)) {
			DEBUGP("%s for unknown call %u\n", 
				strMName[msg], ntohs(*pcid));
			break;
		}
		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
		/* part two of the three-way handshake */
		info->cstate = PPTP_CALL_IN_REP;
		info->pns_call_id = ntohs(pptpReq.icack->callID);
		break;

	case PPTP_CALL_CLEAR_REQUEST:
		/* client requests hangup of call */
		if (info->sstate != PPTP_SESSION_CONFIRMED) {
			DEBUGP("CLEAR_CALL but no session\n");
			break;
		}
		/* FUTURE: iterate over all calls and check if
		 * call ID is valid.  We don't do this without newnat,
		 * because we only know about last call */
		info->cstate = PPTP_CALL_CLEAR_REQ;
		break;
	case PPTP_SET_LINK_INFO:
		break;
	case PPTP_ECHO_REQUEST:
	case PPTP_ECHO_REPLY:
		/* I don't have to explain these ;) */
		break;
	default:
		DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? 
			strMName[msg]:strMName[0], msg);
		/* unknown: no need to create GRE masq table entry */
		break;
	}

	return NF_ACCEPT;
}
BOOLEAN GetPacketInfoFromArguments(_Inout_ OVS_OFPACKET_INFO* pPacketInfo, _Inout_ OVS_PI_RANGE* pPiRange, _In_ const OVS_ARGUMENT_GROUP* pPIGroup, _In_ BOOLEAN isMask)
{
    BOOLEAN haveIpv4 = FALSE;
    OVS_ARGUMENT* pVlanTciArg = NULL, *pEthTypeArg = NULL, *pDatapathInPortArg = NULL;

    OVS_CHECK(pPacketInfo);
    OVS_CHECK(pPiRange);

    for (UINT i = 0; i < pPIGroup->count; ++i)
    {
        OVS_ARGUMENT* pArg = pPIGroup->args + i;
        OVS_ARGTYPE argType = pArg->type;

        switch (argType)
        {
        case OVS_ARGTYPE_PI_DATAPATH_HASH:
            OVS_PI_UPDATE_MAIN_FIELD(pPacketInfo, pPiRange, pArg, UINT32, flowHash);
            break;

        case OVS_ARGTYPE_PI_DATAPATH_RECIRCULATION_ID:
            OVS_PI_UPDATE_MAIN_FIELD(pPacketInfo, pPiRange, pArg, UINT32, recirculationId);
            break;

        case OVS_ARGTYPE_PI_PACKET_PRIORITY:
            OVS_PI_UPDATE_PHYSICAL_FIELD(pPacketInfo, pPiRange, pArg, UINT32, packetPriority);
            break;

        case OVS_ARGTYPE_PI_DP_INPUT_PORT:
            pDatapathInPortArg = pArg;
            EXPECT(_PIFromArg_DatapathInPort(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_PACKET_MARK:
            OVS_PI_UPDATE_PHYSICAL_FIELD(pPacketInfo, pPiRange, pArg, UINT32, packetMark);
            break;

        case OVS_ARGTYPE_PI_TUNNEL_GROUP:
            OVS_CHECK(IsArgTypeGroup(pArg->type));
            EXPECT(_PIFromArg_Tunnel(pArg->data, pPacketInfo, pPiRange, isMask));
            break;

        case OVS_ARGTYPE_PI_ETH_ADDRESS:
        {
            const OVS_PI_ETH_ADDRESS* pEthAddressPI = pArg->data;

            OVS_PI_UPDATE_ETHINFO_ADDRESS(pPacketInfo, pPiRange, source, pEthAddressPI->source);
            OVS_PI_UPDATE_ETHINFO_ADDRESS(pPacketInfo, pPiRange, destination, pEthAddressPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_VLAN_TCI:
            pVlanTciArg = pArg;
            {
                BE16 tci = GET_ARG_DATA(pVlanTciArg, BE16);

                EXPECT(tci & RtlUshortByteSwap(OVS_VLAN_TAG_PRESENT));
                OVS_PI_UPDATE_ETHINFO_FIELD(pPacketInfo, pPiRange, pVlanTciArg, BE16, tci);
            }
            break;

        case OVS_ARGTYPE_PI_ETH_TYPE:
            pEthTypeArg = pArg;
            EXPECT(_GetPIFromArg_EthType(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_IPV4:
            haveIpv4 = TRUE;
            EXPECT(_GetPIFromArg_Ipv4(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_IPV6:
            EXPECT(_GetPIFromArg_Ipv6(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_ARP:
            EXPECT(_GetPIFromArg_Arp(pPacketInfo, pPiRange, pArg, isMask));
            break;

        case OVS_ARGTYPE_PI_MPLS:
        {
            const OVS_PI_MPLS* pMplsPI = pArg->data;

            OVS_PI_UPDATE_NETINFO_FIELD_VALUE(pPacketInfo, pPiRange, mplsTopLabelStackEntry, pMplsPI->mplsLse);
        }
            break;

        case OVS_ARGTYPE_PI_TCP:
        {
            const OVS_PI_TCP* pTcpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pTcpPI->source);
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pTcpPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_TCP_FLAGS:
            OVS_PI_UPDATE_TPINFO_FIELD(pPacketInfo, pPiRange, pArg, BE16, tcpFlags);
            break;

        case OVS_ARGTYPE_PI_UDP:
        {
            const OVS_PI_UDP* pUdpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pUdpPI->source);
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pUdpPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_SCTP:
        {
            const OVS_PI_SCTP* pSctpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, pSctpPI->source);
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, pSctpPI->destination);
        }
            break;

        case OVS_ARGTYPE_PI_ICMP:
        {
            const OVS_PI_ICMP* pIcmpPI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, RtlUshortByteSwap(pIcmpPI->type));
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, RtlUshortByteSwap(pIcmpPI->code));
        }
            break;

        case OVS_ARGTYPE_PI_ICMP6:
        {
            const OVS_PI_ICMP6* pIcmpv6PI = pArg->data;

            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, sourcePort, RtlUshortByteSwap(pIcmpv6PI->type));
            OVS_PI_UPDATE_TPINFO_FIELD_VALUE(pPacketInfo, pPiRange, destinationPort, RtlUshortByteSwap(pIcmpv6PI->code));
        }
            break;

        case OVS_ARGTYPE_PI_NEIGHBOR_DISCOVERY:
            _GetPIFromArg_NeighborDiscovery(pPacketInfo, pPiRange, pArg);
            break;

        default:
            DEBUGP(LOG_ERROR, __FUNCTION__ " unexpected key / mask arg type: %u\n", pArg->type);
            return FALSE;
        }
    }

    if (!pDatapathInPortArg && !isMask)
    {
        OVS_PI_UPDATE_PHYSICAL_FIELD_VALUE(pPacketInfo, pPiRange, packetMark, OVS_INVALID_PORT_NUMBER);
    }

    if (!pVlanTciArg)
    {
        if (!isMask)
        {
            //TODO: we should normally set vlan tci to 0xFFFF in this case.
            //but it used to work with 0 only
            OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, tci, 0);
        }
    }

    if (!pEthTypeArg)
    {
        if (isMask)
        {
            OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, type, OVS_PI_MASK_MATCH_EXACT(UINT16));
        }
        else
        {
            OVS_PI_UPDATE_ETHINFO_FIELD_VALUE(pPacketInfo, pPiRange, type, RtlUshortByteSwap(OVS_ETHERTYPE_802_2));
        }
    }

    return TRUE;
}
Esempio n. 7
0
static void
autofw_expect(struct nf_conn *ct, struct nf_conntrack_expect *exp)
{
	struct nf_nat_range pre_range;
	u_int32_t newdstip, newsrcip;
	u_int16_t port;
	int ret;
	struct nf_conn_help *help;
	struct nf_conn *exp_ct = exp->master;
	struct nf_conntrack_expect *newexp;
	int count;

	/* expect has been removed from expect list, but expect isn't free yet. */
	help = nfct_help(exp_ct);
	DEBUGP("autofw_nat_expected: got ");
	NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);

	spin_lock_bh(&nf_nat_autofw_lock);

	port = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all);
	newdstip = exp->tuple.dst.u3.ip;
	newsrcip = exp->tuple.src.u3.ip;
	if (port < ntohs(help->help.ct_autofw_info.dport[0]) ||
		port > ntohs(help->help.ct_autofw_info.dport[1])) {
		spin_unlock_bh(&nf_nat_autofw_lock);
			return;
	}

	/* Only need to do PRE_ROUTING */
	port -= ntohs(help->help.ct_autofw_info.dport[0]);
	port += ntohs(help->help.ct_autofw_info.to[0]);
	pre_range.flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
	pre_range.min_ip = pre_range.max_ip = newdstip;
	pre_range.min.all = pre_range.max.all = htons(port);
	nf_nat_setup_info(ct, &pre_range, NF_IP_PRE_ROUTING);

	spin_unlock_bh(&nf_nat_autofw_lock);

	/* Add expect again */

	/* alloc will set exp->master = exp_ct */
	newexp = nf_conntrack_expect_alloc(exp_ct);
	if (!newexp)
		return;

	newexp->tuple.src.u3.ip = exp->tuple.src.u3.ip;
	newexp->tuple.dst.protonum = exp->tuple.dst.protonum;
	newexp->mask.src.u3.ip = 0xFFFFFFFF;
	newexp->mask.dst.protonum = 0xFF;

	newexp->tuple.dst.u3.ip = exp->tuple.dst.u3.ip;
	newexp->mask.dst.u3.ip = 0x0;

	for (count = 1; count < NF_CT_TUPLE_L3SIZE; count++) {
		newexp->tuple.src.u3.all[count] = 0x0;
		newexp->tuple.dst.u3.all[count] = 0x0;
	}

	newexp->mask.dst.u.all = 0x0;
	newexp->mask.src.u.all = 0x0;
	newexp->mask.src.l3num = 0x0;

	newexp->expectfn = autofw_expect;
	newexp->helper = NULL;
	newexp->flags = 0;

	/*
	 * exp->timeout.expires will set as
	 * (jiffies + helper->timeout * HZ), when insert exp.
	*/
	ret = nf_conntrack_expect_related(newexp);
	if (ret == 0)
		nf_conntrack_expect_put(newexp);
}
Esempio n. 8
0
/* The core of recursive retrieving.  Endless recursion is avoided by
   having all URL-s stored to a linked list of URL-s, which is checked
   before loading any URL.  That way no URL can get loaded twice.

   The function also supports specification of maximum recursion depth
   and a number of other goodies.  */
uerr_t
recursive_retrieve (const char *file, const char *this_url)
{
  char *constr, *filename, *newloc;
  char *canon_this_url = NULL;
  int dt, inl;
  int this_url_ftp;            /* See below the explanation */
  uerr_t err;
  struct urlinfo *rurl;
  urlpos *url_list, *cur_url;
  char *rfile; /* For robots */
  struct urlinfo *u;

  assert (this_url != NULL);
  assert (file != NULL);
  /* If quota was exceeded earlier, bail out.  */
  if (opt.quota && (opt.downloaded > opt.quota))
    return QUOTEXC;
  /* Cache the current URL in the list.  */
  if (first_time)
    {
      ulist = add_slist (ulist, this_url, 0);
      urls_downloaded = NULL;
      urls_html = NULL;
      /* Enter this_url to the slist, in original and "enhanced" form.  */
      u = newurl ();
      err = parseurl (this_url, u, 0);
      if (err == URLOK)
	{
	  ulist = add_slist (ulist, u->url, 0);
	  urls_downloaded = add_url (urls_downloaded, u->url, file);
	  urls_html = add_slist (urls_html, file, NOSORT);
	  if (opt.no_parent)
	    base_dir = xstrdup (u->dir); /* Set the base dir.  */
	  /* Set the canonical this_url to be sent as referer.  This
	     problem exists only when running the first time.  */
	  canon_this_url = xstrdup (u->url);
	}
      else
	{
	  DEBUGP (("Double yuck!  The *base* URL is broken.\n"));
	  base_dir = NULL;
	}
      freeurl (u, 1);
      depth = 1;
      robots_host = NULL;
      forbidden = NULL;
      first_time = 0;
    }
  else
    ++depth;

  /* Bail out if opt.reclevel is exceeded.  */
  if ((opt.reclevel != 0) && (depth > opt.reclevel))
    {
      DEBUGP (("Recursion depth %d exceeded max. depth %d.\n",
	       depth, opt.reclevel));
      --depth;
      return RECLEVELEXC;
    }

  /* Determine whether this_url is an FTP URL.  If it is, it means
     that the retrieval is done through proxy.  In that case, FTP
     links will be followed by default and recursion will not be
     turned off when following them.  */
  this_url_ftp = (urlproto (this_url) == URLFTP);

  /* Get the URL-s from an HTML file: */
  url_list = get_urls_html (file,
			    canon_this_url ? canon_this_url : this_url, 0);

  /* Decide what to do with each of the URLs.  A URL will be loaded if
     it meets several requirements, discussed later.  */
  for (cur_url = url_list; cur_url; cur_url = cur_url->next)
    {
      /* If quota was exceeded earlier, bail out.  */
      if (opt.quota && (opt.downloaded > opt.quota))
	break;
      /* Parse the URL for convenient use in other functions, as well
	 as to get the optimized form.  It also checks URL integrity.  */
      u = newurl ();
      if (parseurl (cur_url->url, u, 0) != URLOK)
	{
	  DEBUGP (("Yuck!  A bad URL.\n"));
	  freeurl (u, 1);
	  continue;
	}
      if (u->proto == URLFILE)
	{
	  DEBUGP (("Nothing to do with file:// around here.\n"));
	  freeurl (u, 1);
	  continue;
	}
      assert (u->url != NULL);
      constr = xstrdup (u->url);

      /* Several checkings whether a file is acceptable to load:
	 1. check if URL is ftp, and we don't load it
	 2. check for relative links (if relative_only is set)
	 3. check for domain
	 4. check for no-parent
	 5. check for excludes && includes
	 6. check for suffix
	 7. check for same host (if spanhost is unset), with possible
	 gethostbyname baggage
	 8. check for robots.txt

	 Addendum: If the URL is FTP, and it is to be loaded, only the
	 domain and suffix settings are "stronger".

	 Note that .html and (yuck) .htm will get loaded
	 regardless of suffix rules (but that is remedied later with
	 unlink).

	 More time- and memory- consuming tests should be put later on
	 the list.  */

      /* inl is set if the URL we are working on (constr) is stored in
	 ulist.  Using it is crucial to avoid the incessant calls to
	 in_slist, which is quite slow.  */
      inl = in_slist (ulist, constr);

      /* If it is FTP, and FTP is not followed, chuck it out.  */
      if (!inl)
	if (u->proto == URLFTP && !opt.follow_ftp && !this_url_ftp)
	  {
	    DEBUGP (("Uh, it is FTP but i'm not in the mood to follow FTP.\n"));
	    ulist = add_slist (ulist, constr, 0);
	    inl = 1;
	  }
      /* If it is absolute link and they are not followed, chuck it
	 out.  */
      if (!inl && u->proto != URLFTP)
	if (opt.relative_only && !(cur_url->flags & URELATIVE))
	  {
	    DEBUGP (("It doesn't really look like a relative link.\n"));
	    ulist = add_slist (ulist, constr, 0);
	    inl = 1;
	  }
      /* If its domain is not to be accepted/looked-up, chuck it out.  */
      if (!inl)
	if (!accept_domain (u))
	  {
	    DEBUGP (("I don't like the smell of that domain.\n"));
	    ulist = add_slist (ulist, constr, 0);
	    inl = 1;
	  }
      /* Check for parent directory.  */
      if (!inl && opt.no_parent
	  /* If the new URL is FTP and the old was not, ignore
             opt.no_parent.  */
	  && !(!this_url_ftp && u->proto == URLFTP))
	{
	  /* Check for base_dir first.  */
	  if (!(base_dir && frontcmp (base_dir, u->dir)))
	    {
	      /* Failing that, check for parent dir.  */
	      struct urlinfo *ut = newurl ();
	      if (parseurl (this_url, ut, 0) != URLOK)
		DEBUGP (("Double yuck!  The *base* URL is broken.\n"));
	      else if (!frontcmp (ut->dir, u->dir))
		{
		  /* Failing that too, kill the URL.  */
		  DEBUGP (("Trying to escape parental guidance with no_parent on.\n"));
		  ulist = add_slist (ulist, constr, 0);
		  inl = 1;
		}
	      freeurl (ut, 1);
	    }
	}
      /* If the file does not match the acceptance list, or is on the
	 rejection list, chuck it out.  The same goes for the
	 directory exclude- and include- lists.  */
      if (!inl && (opt.includes || opt.excludes))
	{
	  if (!accdir (u->dir, ALLABS))
	    {
	      DEBUGP (("%s (%s) is excluded/not-included.\n", constr, u->dir));
	      ulist = add_slist (ulist, constr, 0);
	      inl = 1;
	    }
	}
      if (!inl)
	{
	  char *suf = NULL;
	  /* We check for acceptance/rejection rules only for non-HTML
	     documents.  Since we don't know whether they really are
	     HTML, it will be deduced from (an OR-ed list):

	     1) u->file is "" (meaning it is a directory)
	     2) suffix exists, AND:
	     a) it is "html", OR
	     b) it is "htm"

	     If the file *is* supposed to be HTML, it will *not* be
	     subject to acc/rej rules.  That's why the `!'.  */
	  if (!
	      (!*u->file
	       || (((suf = suffix (constr)) != NULL)
		   && (!strcmp (suf, "html") || !strcmp (suf, "htm")))))
	    {
	      if (!acceptable (u->file))
		{
		  DEBUGP (("%s (%s) does not match acc/rej rules.\n",
			  constr, u->file));
		  ulist = add_slist (ulist, constr, 0);
		  inl = 1;
		}
	    }
	  FREE_MAYBE (suf);
	}
      /* Optimize the URL (which includes possible DNS lookup) only
	 after all other possibilities have been exhausted.  */
      if (!inl)
	{
	  if (!opt.simple_check)
	    opt_url (u);
	  else
	    {
	      char *p;
	      /* Just lowercase the hostname.  */
	      for (p = u->host; *p; p++)
		*p = tolower (*p);
	      free (u->url);
	      u->url = str_url (u, 0);
	    }
	  free (constr);
	  constr = xstrdup (u->url);
	  inl = in_slist (ulist, constr);
	  if (!inl && !((u->proto == URLFTP) && !this_url_ftp))
	    if (!opt.spanhost && this_url && !same_host (this_url, constr))
	      {
		DEBUGP (("This is not the same hostname as the parent's.\n"));
		ulist = add_slist (ulist, constr, 0);
		inl = 1;
	      }
	}
      /* What about robots.txt?  */
      if (!inl && opt.use_robots && u->proto == URLHTTP)
	{
	  /* Since Wget knows about only one set of robot rules at a
	     time, /robots.txt must be reloaded whenever a new host is
	     accessed.

	     robots_host holds the host the current `forbid' variable
	     is assigned to.  */
	  if (!robots_host || !same_host (robots_host, u->host))
	    {
	      FREE_MAYBE (robots_host);
	      /* Now make robots_host the new host, no matter what the
		 result will be.  So if there is no /robots.txt on the
		 site, Wget will not retry getting robots all the
		 time.  */
	      robots_host = xstrdup (u->host);
	      free_vec (forbidden);
	      forbidden = NULL;
	      err = retrieve_robots (constr, ROBOTS_FILENAME);
	      if (err == ROBOTSOK)
		{
		  rurl = robots_url (constr, ROBOTS_FILENAME);
		  rfile = url_filename (rurl);
		  forbidden = parse_robots (rfile);
		  freeurl (rurl, 1);
		  free (rfile);
		}
	    }

	  /* Now that we have (or don't have) robots, we can check for
	     them.  */
	  if (!robots_match (u, forbidden))
	    {
	      DEBUGP (("Stuffing %s because %s forbids it.\n", this_url,
		       ROBOTS_FILENAME));
	      ulist = add_slist (ulist, constr, 0);
	      inl = 1;
	    }
	}

      filename = NULL;
      /* If it wasn't chucked out, do something with it.  */
      if (!inl)
	{
	  DEBUGP (("I've decided to load it -> "));
	  /* Add it to the list of already-loaded URL-s.  */
	  ulist = add_slist (ulist, constr, 0);
	  /* Automatically followed FTPs will *not* be downloaded
	     recursively.  */
	  if (u->proto == URLFTP)
	    {
	      /* Don't you adore side-effects?  */
	      opt.recursive = 0;
	    }
	  /* Reset its type.  */
	  dt = 0;
	  /* Retrieve it.  */
	  retrieve_url (constr, &filename, &newloc,
		       canon_this_url ? canon_this_url : this_url, &dt);
	  if (u->proto == URLFTP)
	    {
	      /* Restore...  */
	      opt.recursive = 1;
	    }
	  if (newloc)
	    {
	      free (constr);
	      constr = newloc;
	    }
	  /* In case of convert_links: If there was no error, add it to
	     the list of downloaded URLs.  We might need it for
	     conversion.  */
	  if (opt.convert_links && filename)
	    {
	      if (dt & RETROKF)
		{
		  urls_downloaded = add_url (urls_downloaded, constr, filename);
		  /* If the URL is HTML, note it.  */
		  if (dt & TEXTHTML)
		    urls_html = add_slist (urls_html, filename, NOSORT);
		}
	    }
	  /* If there was no error, and the type is text/html, parse
	     it recursively.  */
	  if (dt & TEXTHTML)
	    {
	      if (dt & RETROKF)
		recursive_retrieve (filename, constr);
	    }
	  else
	    DEBUGP (("%s is not text/html so we don't chase.\n",
		     filename ? filename: "(null)"));
	  /* If an suffix-rejected file was loaded only because it was HTML,
	     undo the error now */
	  if (opt.delete_after || (filename && !acceptable (filename)))
	    {
	      logprintf (LOG_VERBOSE,
			 (opt.delete_after ? _("Removing %s.\n")
			  : _("Removing %s since it should be rejected.\n")),
			 filename);
	      if (unlink (filename))
		logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
	      dt &= ~RETROKF;
	    }
	  /* If everything was OK, and links are to be converted, let's
	     store the local filename.  */
	  if (opt.convert_links && (dt & RETROKF) && (filename != NULL))
	    {
	      cur_url->flags |= UABS2REL;
	      cur_url->local_name = xstrdup (filename);
	    }
	}
      DEBUGP (("%s already in list, so we don't load.\n", constr));
      /* Free filename and constr.  */
      FREE_MAYBE (filename);
      FREE_MAYBE (constr);
      freeurl (u, 1);
      /* Increment the pbuf for the appropriate size.  */
    }
  if (opt.convert_links)
    convert_links (file, url_list);
  /* Free the linked list of URL-s.  */
  free_urlpos (url_list);
  /* Free the canonical this_url.  */
  FREE_MAYBE (canon_this_url);
  /* Decrement the recursion depth.  */
  --depth;
  if (opt.quota && (opt.downloaded > opt.quota))
    return QUOTEXC;
  else
    return RETROK;
}
Esempio n. 9
0
/* Simple calls to convert_links will often fail because only the
   downloaded files are converted, and Wget cannot know which files
   will be converted in the future.  So, if we have file fileone.html
   with:

   <a href=/c/something.gif>

   and /c/something.gif was not downloaded because it exceeded the
   recursion depth, the reference will *not* be changed.

   However, later we can encounter /c/something.gif from an "upper"
   level HTML (let's call it filetwo.html), and it gets downloaded.

   But now we have a problem because /c/something.gif will be
   correctly transformed in filetwo.html, but not in fileone.html,
   since Wget could not have known that /c/something.gif will be
   downloaded in the future.

   This is why Wget must, after the whole retrieval, call
   convert_all_links to go once more through the entire list of
   retrieved HTML-s, and re-convert them.

   All the downloaded HTMLs are kept in urls_html, and downloaded URLs
   in urls_downloaded.  From these two lists information is
   extracted.  */
void
convert_all_links (void)
{
  uerr_t res;
  urlpos *l1, *l2, *urls;
  struct urlinfo *u;
  slist *html;
  urlpos *urlhtml;

  for (html = urls_html; html; html = html->next)
    {
      DEBUGP (("Rescanning %s\n", html->string));
      /* Determine the URL of the HTML file.  get_urls_html will need
	 it.  */
      for (urlhtml = urls_downloaded; urlhtml; urlhtml = urlhtml->next)
	if (!strcmp (urlhtml->local_name, html->string))
	  break;
      if (urlhtml)
	DEBUGP (("It should correspond to %s.\n", urlhtml->url));
      else
	DEBUGP (("I cannot find the corresponding URL.\n"));
      /* Parse the HTML file...  */
      urls = get_urls_html (html->string, urlhtml ? urlhtml->url : NULL, 1);
      if (!urls)
	continue;
      for (l1 = urls; l1; l1 = l1->next)
	{
	  /* The URL must be in canonical form to be compared.  */
	  u = newurl ();
	  res = parseurl (l1->url, u, 0);
	  if (res != URLOK)
	    {
	      freeurl (u, 1);
	      continue;
	    }
	  /* We decide the direction of conversion according to whether
	     a URL was downloaded.  Downloaded URLs will be converted
	     ABS2REL, whereas non-downloaded will be converted REL2ABS.
	     Note: not yet implemented; only ABS2REL works.  */
	  for (l2 = urls_downloaded; l2; l2 = l2->next)
	    if (!strcmp (l2->url, u->url))
	      {
		DEBUGP (("%s flagged for conversion, local %s\n",
			 l2->url, l2->local_name));
		break;
	      }
	  /* Clear the flags.  */
	  l1->flags &= ~ (UABS2REL | UREL2ABS);
	  /* Decide on the conversion direction.  */
	  if (l2)
	    {
	      l1->flags |= UABS2REL;
	      l1->local_name = xstrdup (l2->local_name);
	    }
	  else
	    {
	      l1->flags |= UREL2ABS;
	      l1->local_name = NULL;
	    }
	  freeurl (u, 1);
	}
      /* Convert the links in the file.  */
      convert_links (html->string, urls);
      /* Free the data.  */
      free_urlpos (urls);
    }
}
/* FIXME: This should be in userspace.  Later. */
static int h245_help(const struct iphdr *iph, size_t len,
		     struct ip_conntrack *ct,
		     enum ip_conntrack_info ctinfo)
{
	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
	unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
	unsigned char *data_limit;
	u_int32_t tcplen = len - iph->ihl * 4;
	u_int32_t datalen = tcplen - tcph->doff * 4;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
	struct ip_conntrack_expect expect, *exp = &expect;
	struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
	u_int16_t data_port;
	u_int32_t data_ip;
	unsigned int i;

	DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
		NIPQUAD(iph->saddr), ntohs(tcph->source),
		NIPQUAD(iph->daddr), ntohs(tcph->dest));

	/* Can't track connections formed before we registered */
	if (!info)
		return NF_ACCEPT;
		
	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header or too short packet? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
		DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
		return NF_ACCEPT;
	}

	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			      csum_partial((char *)tcph, tcplen, 0))) {
		DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		       tcph, tcplen, NIPQUAD(iph->saddr),
		       NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}

	data_limit = (unsigned char *) data + datalen;
	/* bytes: 0123   45
	          ipadrr port */
	for (i = 0; data < (data_limit - 5); data++, i++) {
		data_ip = *((u_int32_t *)data);
		if (data_ip == iph->saddr) {
			data_port = *((u_int16_t *)(data + 4));
			memset(&expect, 0, sizeof(expect));
			/* update the H.225 info */
			DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
				NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
				NIPQUAD(iph->saddr), ntohs(data_port));
			LOCK_BH(&ip_h323_lock);
			info->is_h225 = H225_PORT + 1;
			exp_info->port = data_port;
			exp_info->dir = dir;
			exp_info->offset = i;

			exp->seq = ntohl(tcph->seq) + i;
		    
			exp->tuple = ((struct ip_conntrack_tuple)
				{ { ct->tuplehash[!dir].tuple.src.ip,
				    { 0 } },
				  { data_ip,
				    { udp: { port: data_port } },
				    IPPROTO_UDP }});
Esempio n. 11
0
bool
ssl_check_certificate (int fd, const char *host)
{
  X509 *cert;
  GENERAL_NAMES *subjectAltNames;
  char common_name[256];
  long vresult;
  bool success = true;
  bool alt_name_checked = false;

  /* If the user has specified --no-check-cert, we still want to warn
     him about problems with the server's certificate.  */
  const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");

  struct openssl_transport_context *ctx = fd_transport_context (fd);
  SSL *conn = ctx->conn;
  assert (conn != NULL);

  cert = SSL_get_peer_certificate (conn);
  if (!cert)
    {
      logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
                 severity, quotearg_style (escape_quoting_style, host));
      success = false;
      goto no_cert;             /* must bail out since CERT is NULL */
    }

  IF_DEBUG
    {
      char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
      char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
      DEBUGP (("certificate:\n  subject: %s\n  issuer:  %s\n",
               quotearg_n_style (0, escape_quoting_style, subject),
               quotearg_n_style (1, escape_quoting_style, issuer)));
      OPENSSL_free (subject);
      OPENSSL_free (issuer);
    }

  vresult = SSL_get_verify_result (conn);
  if (vresult != X509_V_OK)
    {
      char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
      logprintf (LOG_NOTQUIET,
                 _("%s: cannot verify %s's certificate, issued by %s:\n"),
                 severity, quotearg_n_style (0, escape_quoting_style, host),
                 quote_n (1, issuer));
      /* Try to print more user-friendly (and translated) messages for
         the frequent verification errors.  */
      switch (vresult)
        {
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
          logprintf (LOG_NOTQUIET,
                     _("  Unable to locally verify the issuer's authority.\n"));
          break;
        case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
          logprintf (LOG_NOTQUIET,
                     _("  Self-signed certificate encountered.\n"));
          break;
        case X509_V_ERR_CERT_NOT_YET_VALID:
          logprintf (LOG_NOTQUIET, _("  Issued certificate not yet valid.\n"));
          break;
        case X509_V_ERR_CERT_HAS_EXPIRED:
          logprintf (LOG_NOTQUIET, _("  Issued certificate has expired.\n"));
          break;
        default:
          /* For the less frequent error strings, simply provide the
             OpenSSL error message.  */
          logprintf (LOG_NOTQUIET, "  %s\n",
                     X509_verify_cert_error_string (vresult));
        }
      success = false;
      /* Fall through, so that the user is warned about *all* issues
         with the cert (important with --no-check-certificate.)  */
    }

  /* Check that HOST matches the common name in the certificate.
     #### The following remains to be done:

     - When matching against common names, it should loop over all
       common names and choose the most specific one, i.e. the last
       one, not the first one, which the current code picks.

     - Ensure that ASN1 strings from the certificate are encoded as
       UTF-8 which can be meaningfully compared to HOST.  */

  subjectAltNames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL);

  if (subjectAltNames)
    {
      /* Test subject alternative names */

      /* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)?
       * Signal it by host_in_octet_string. */
      ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host);

      int numaltnames = sk_GENERAL_NAME_num (subjectAltNames);
      int i;
      for (i=0; i < numaltnames; i++)
        {
          const GENERAL_NAME *name =
            sk_GENERAL_NAME_value (subjectAltNames, i);
          if (name)
            {
              if (host_in_octet_string)
                {
                  if (name->type == GEN_IPADD)
                    {
                      /* Check for ipAddress */
                      /* TODO: Should we convert between IPv4-mapped IPv6
                       * addresses and IPv4 addresses? */
                      alt_name_checked = true;
                      if (!ASN1_STRING_cmp (host_in_octet_string,
                            name->d.iPAddress))
                        break;
                    }
                }
              else if (name->type == GEN_DNS)
                {
                  /* dNSName should be IA5String (i.e. ASCII), however who
                   * does trust CA? Convert it into UTF-8 for sure. */
                  unsigned char *name_in_utf8 = NULL;

                  /* Check for dNSName */
                  alt_name_checked = true;

                  if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName))
                    {
                      /* Compare and check for NULL attack in ASN1_STRING */
                      if (pattern_match ((char *)name_in_utf8, host) &&
                            (strlen ((char *)name_in_utf8) ==
                                (size_t) ASN1_STRING_length (name->d.dNSName)))
                        {
                          OPENSSL_free (name_in_utf8);
                          break;
                        }
                      OPENSSL_free (name_in_utf8);
                    }
                }
            }
        }
      sk_GENERAL_NAME_free (subjectAltNames);
      if (host_in_octet_string)
        ASN1_OCTET_STRING_free(host_in_octet_string);

      if (alt_name_checked == true && i >= numaltnames)
        {
          logprintf (LOG_NOTQUIET,
              _("%s: no certificate subject alternative name matches\n"
                "\trequested host name %s.\n"),
                     severity, quote_n (1, host));
          success = false;
        }
    }

  if (alt_name_checked == false)
    {
      /* Test commomName */
      X509_NAME *xname = X509_get_subject_name(cert);
      common_name[0] = '\0';
      X509_NAME_get_text_by_NID (xname, NID_commonName, common_name,
                                 sizeof (common_name));

      if (!pattern_match (common_name, host))
        {
          logprintf (LOG_NOTQUIET, _("\
    %s: certificate common name %s doesn't match requested host name %s.\n"),
                     severity, quote_n (0, common_name), quote_n (1, host));
          success = false;
        }
Esempio n. 12
0
/* FIXME: This should be in userspace.  Later. */
static int help(struct sk_buff **pskb,
		struct ip_conntrack *ct,
		enum ip_conntrack_info ctinfo)
{
	int ret = NF_DROP;
	struct tcphdr _tcph, *th;
	char *data, *mb_ptr;
	unsigned int datalen, dataoff;


	//struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
	//unsigned int tcplen = len - iph->ihl * 4;
	//unsigned int datalen = tcplen - tcph->doff * 4;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack_expect *exp;
	struct ip_ct_mms_expect _emmi, *exp_mms_info = &_emmi;
	
	u_int32_t mms_ip;
	u_int16_t mms_proto;
	char mms_proto_string[8];
	u_int16_t mms_port;
	char *mms_string_b, *mms_string_e, *mms_padding_e;
	     
	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
		DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header? */
	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
				sizeof(_tcph), &_tcph);
	if (!th)
		return NF_ACCEPT;

	/* No data ? */
	dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
	datalen = (*pskb)->len - dataoff;
	if (dataoff >= (*pskb)->len)
		return NF_ACCEPT;

	LOCK_BH(&mms_buffer_lock);
	mb_ptr = skb_header_pointer(*pskb, dataoff,
				    (*pskb)->len - dataoff, mms_buffer);
	BUG_ON(mb_ptr == NULL);

	data = mb_ptr;

#if 0
	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
	    csum_partial((char *)tcph, tcplen, 0))) {
		DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		       tcph, tcplen, NIPQUAD(iph->saddr),
		       NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}
#endif
	
	/* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP
	 * payload */

	/* FIXME: There is an issue with only looking at this packet: before
	 * this packet, the client has already sent a packet to the server with
	 * the server's hostname according to the client (think of it as the
	 * "Host: " header in HTTP/1.1). The server will break the connection
	 * if this doesn't correspond to its own host header. The client can
	 * also connect to an IP address; if it's the server's IP address, it
	 * will not break the connection. When doing DNAT on a connection where
	 * the client uses a server's IP address, the nat module should detect
	 * this and change this string accordingly to the DNATed address. This
	 * should probably be done by checking for an IP address, then storing
	 * it as a member of struct ip_ct_mms_expect and checking for it in
	 * ip_nat_mms...
	 */
	if ((MMS_SRV_MSG_OFFSET < datalen) && 
	    ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
		DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", 
		       (u8)*(data+36), (u8)*(data+37), 
		       (u8)*(data+38), (u8)*(data+39),
		       datalen);
		if (parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
		             &mms_string_b, &mms_string_e, &mms_padding_e))
			if (net_ratelimit())
				/* FIXME: more verbose debugging ? */
				printk(KERN_WARNING
				       "ip_conntrack_mms: Unable to parse "
				       "data payload\n");

		sprintf(mms_proto_string, "(%u)", mms_proto);
		DEBUGP("ip_conntrack_mms: adding %s expectation "
		       "%u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
		       mms_proto == IPPROTO_TCP ? "TCP"
		       : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
		       NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
		       NIPQUAD(mms_ip),
		       mms_port);
		
		/* it's possible that the client will just ask the server to
		 * tunnel the stream over the same TCP session (from port
		 * 1755): there's shouldn't be a need to add an expectation in
		 * that case, but it makes NAT packet mangling so much easier
		 * */

		DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);

		exp = ip_conntrack_expect_alloc();
		if (!exp) {
			ret = NF_DROP;
			goto out;
		}
		
		exp_mms_info->offset  = (mms_string_b - data);
		exp_mms_info->len     = (mms_string_e  - mms_string_b);
		exp_mms_info->padding = (mms_padding_e - mms_string_e);
		exp_mms_info->port    = mms_port;
		
		DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), "
		       "len=%d, padding=%u\n", exp->seq, (mms_string_e - data),
		       exp_mms_info->len, exp_mms_info->padding);
		
		exp->tuple = ((struct ip_conntrack_tuple)
		              { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
		              { mms_ip,
Esempio n. 13
0
static int __init init(void)
{
	int port, ret;
	char *tmpname;

	/* If no port given, default to standard RSH port */
	if (ports[0] == 0)
		ports[0] = RSH_PORT;

	/* the check on reserved port <1023 doesn't work with Legato */
	/* for Legato NetWorker, the check should be that port <= 9936 */ 

	if (range == 0) 
		range = 1023;

	/* Legato uses range [ 7937 : 9936 ] -> 7937 by default */

	rangemask = 0xffff ^ range; /* defaults to = 0xfc00 */

	for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
		memset(&rsh_helpers[port], 0, sizeof(struct ip_conntrack_helper));

		tmpname = &rsh_names[port][0];
		if (ports[port] == RSH_PORT)
			sprintf(tmpname, "rsh");
		else
			sprintf(tmpname, "rsh-%d", ports[port]);
		rsh_helpers[port].name = tmpname;

		rsh_helpers[port].me = THIS_MODULE;
		rsh_helpers[port].max_expected = 1;
		rsh_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT;
		rsh_helpers[port].timeout = 0;

		rsh_helpers[port].tuple.dst.protonum = IPPROTO_TCP;
		rsh_helpers[port].mask.dst.protonum = 0xffff;

		/* RSH must come from ports 0:1023 to ports[port] (514) */
		rsh_helpers[port].tuple.src.u.tcp.port = htons(ports[port]);
		rsh_helpers[port].mask.src.u.tcp.port = htons(rangemask);
		rsh_helpers[port].mask.dst.u.tcp.port = htons(rangemask);

		rsh_helpers[port].help = help;

		DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]);
		DEBUGP("helper match ip   %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
			NIPQUAD(rsh_helpers[port].tuple.src.ip),
			ntohs(rsh_helpers[port].tuple.src.u.tcp.port),
			NIPQUAD(rsh_helpers[port].tuple.dst.ip),
			ntohs(rsh_helpers[port].tuple.dst.u.tcp.port));
		DEBUGP("helper match mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
			NIPQUAD(rsh_helpers[port].mask.src.ip),
			ntohs(rsh_helpers[port].mask.src.u.tcp.port),
			NIPQUAD(rsh_helpers[port].mask.dst.ip),
			ntohs(rsh_helpers[port].mask.dst.u.tcp.port));

		ret = ip_conntrack_helper_register(&rsh_helpers[port]);

		if (ret) {
			printk("ERROR registering port %d\n",
				ports[port]);
			fini();
			return -EBUSY;
		}
		ports_n_c++;
	}
	return 0;
}
Esempio n. 14
0
/* FIXME: This should be in userspace.  Later. */
static int help(const struct iphdr *iph, size_t len,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	/* tcplen not negative guarenteed by ip_conntrack_tcp.c */
	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
	const char *data = (const char *) tcph + tcph->doff * 4;
	u_int32_t tcplen = len - iph->ihl * 4;
	int dir = CTINFO2DIR(ctinfo);
        struct ip_conntrack_expect expect, *exp = &expect;
        struct ip_ct_rsh_expect *exp_rsh_info = &exp->help.exp_rsh_info;
	u_int16_t port;
	int maxoctet;

	/*  note that "maxoctet" is used to maintain sanity (8 was the
 	 *  original array size used in rshd/glibc) -- is there a
	 *  vulnerability in rshd.c in the looped port *= 10?
 	 */


	DEBUGP("entered\n");

	/* bail if packet is not from RSH client */
	if (dir == IP_CT_DIR_REPLY)
		return NF_ACCEPT;

	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
		DEBUGP("tcplen = %u\n", (unsigned) tcplen);
		return NF_ACCEPT;
	}

	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			 csum_partial((char *) tcph, tcplen, 0))) {
		DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		     tcph, tcplen, NIPQUAD(iph->saddr),
		     NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}

	/* find the rsh stderr port */
	maxoctet = 4;
	port = 0;
	for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) {
		if (*data < 0)
			return(1);
		if (*data == 0)
			break;
		if (*data < 48 || *data > 57) {
			DEBUGP("these aren't the packets you're looking for ..\n");
			return NF_ACCEPT;
		}
		port = port * 10 + ( *data - 48 );
	}

	/* dont relate sessions that try to expose the client */
	DEBUGP("found port %u\n", port);
	if (port > range) {
		DEBUGP("skipping, expected port size is greater than range!\n");
		return NF_ACCEPT;
	}


	LOCK_BH(&ip_rsh_lock);

	/*  new(,related) connection is;
	 *          reply + dst (uint)port + src port (0:1023)
	 */
	memset(&expect, 0, sizeof(expect));

	/*  save some discovered data, in case someone ever wants to write
	 *  a NAT module for this bastard ..
	 */
	exp_rsh_info->port = port;

	DEBUGP("wrote info port=%u\n", exp_rsh_info->port);


	/* Watch out, Radioactive-Man! */
	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
	exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
	exp->tuple.src.u.tcp.port = 0;
	exp->tuple.dst.u.tcp.port = htons(exp_rsh_info->port);
	exp->tuple.dst.protonum = IPPROTO_TCP;

	exp->mask.src.ip = 0xffffffff;
	exp->mask.dst.ip = 0xffffffff;

	exp->mask.src.u.tcp.port = htons(rangemask);
	exp->mask.dst.u.tcp.port = htons(0xffff);
	exp->mask.dst.protonum = 0xffff;

	exp->expectfn = NULL;

	ip_conntrack_expect_related(ct, &expect);

	DEBUGP("expect related ip   %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
		NIPQUAD(exp->tuple.src.ip),
		ntohs(exp->tuple.src.u.tcp.port),
		NIPQUAD(exp->tuple.dst.ip),
		ntohs(exp->tuple.dst.u.tcp.port));

	DEBUGP("expect related mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
		NIPQUAD(exp->mask.src.ip),
		ntohs(exp->mask.src.u.tcp.port),
		NIPQUAD(exp->mask.dst.ip),
		ntohs(exp->mask.dst.u.tcp.port));
	UNLOCK_BH(&ip_rsh_lock);

	return NF_ACCEPT;
}
Esempio n. 15
0
/*
 * Find lo/hi client ports (if any) in transport header
 * In:
 *   ptcp, tcplen = packet
 *   tranoff, tranlen = buffer to search
 *
 * Out:
 *   pport_lo, pport_hi = lo/hi ports (host endian)
 *
 * Returns nonzero if any client ports found
 *
 * Note: it is valid (and expected) for the client to request multiple
 * transports, so we need to parse the entire line.
 */
static int
rtsp_parse_transport(char* ptran, uint tranlen,
                     struct ip_ct_rtsp_expect* prtspexp)
{
	int     rc = 0;
	uint    off = 0;
	
	if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
	    nf_strncasecmp(ptran, "Transport:", 10) != 0) {
		DEBUGP("sanity check failed\n");
		return 0;
	}
	
	DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
	off += 10;
	SKIP_WSPACE(ptran, tranlen, off);
	
	/* Transport: tran;field;field=val,tran;field;field=val,... */
	while (off < tranlen) {
		const char* pparamend;
		uint        nextparamoff;
		
		pparamend = memchr(ptran+off, ',', tranlen-off);
		pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
		nextparamoff = pparamend-ptran;
		
		while (off < nextparamoff) {
			const char* pfieldend;
			uint        nextfieldoff;
			
			pfieldend = memchr(ptran+off, ';', nextparamoff-off);
			nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
		   
			if (strncmp(ptran+off, "client_port=", 12) == 0) {
				u_int16_t   port;
				uint        numlen;
		    
				off += 12;
				numlen = nf_strtou16(ptran+off, &port);
				off += numlen;
				if (prtspexp->loport != 0 && prtspexp->loport != port)
					DEBUGP("multiple ports found, port %hu ignored\n", port);
				else {
					DEBUGP("lo port found : %hu\n", port);
					prtspexp->loport = prtspexp->hiport = port;
					if (ptran[off] == '-') {
						off++;
						numlen = nf_strtou16(ptran+off, &port);
						off += numlen;
						prtspexp->pbtype = pb_range;
						prtspexp->hiport = port;
						
						// If we have a range, assume rtp:
						// loport must be even, hiport must be loport+1
						if ((prtspexp->loport & 0x0001) != 0 ||
						    prtspexp->hiport != prtspexp->loport+1) {
							DEBUGP("incorrect range: %hu-%hu, correcting\n",
							       prtspexp->loport, prtspexp->hiport);
							prtspexp->loport &= 0xfffe;
							prtspexp->hiport = prtspexp->loport+1;
						}
					} else if (ptran[off] == '/') {
						off++;
						numlen = nf_strtou16(ptran+off, &port);
						off += numlen;
						prtspexp->pbtype = pb_discon;
						prtspexp->hiport = port;
					}
					rc = 1;
				}
			}
			
			/*
			 * Note we don't look for the destination parameter here.
			 * If we are using NAT, the NAT module will handle it.  If not,
			 * and the client is sending packets elsewhere, the expectation
			 * will quietly time out.
			 */
			
			off = nextfieldoff;
		}
		
		off = nextparamoff;
	}
	
	return rc;
}
Esempio n. 16
0
File: gnutls.c Progetto: mirror/wget
bool
ssl_init (void)
{
  /* Becomes true if GnuTLS is initialized. */
  static bool ssl_initialized = false;
  const char *ca_directory;
  DIR *dir;
  int ncerts = -1;

  /* GnuTLS should be initialized only once. */
  if (ssl_initialized)
    return true;

  gnutls_global_init ();
  gnutls_certificate_allocate_credentials (&credentials);
  gnutls_certificate_set_verify_flags (credentials,
                                       GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

#if GNUTLS_VERSION_MAJOR >= 3
  if (!opt.ca_directory)
    ncerts = gnutls_certificate_set_x509_system_trust (credentials);
#endif

  /* If GnuTLS version is too old or CA loading failed, fallback to old behaviour.
   * Also use old behaviour if the CA directory is user-provided.  */
  if (ncerts <= 0)
    {
      ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
      if ((dir = opendir (ca_directory)) == NULL)
        {
          if (opt.ca_directory && *opt.ca_directory)
            logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
                       opt.ca_directory);
        }
      else
        {
          struct hash_table *inode_map = hash_table_new (196, NULL, NULL);
          struct dirent *dent;
          size_t dirlen = strlen(ca_directory);
          int rc;

          ncerts = 0;

          while ((dent = readdir (dir)) != NULL)
            {
              struct stat st;
              size_t ca_file_length = dirlen + strlen(dent->d_name) + 2;
              char *ca_file = alloca(ca_file_length);

              snprintf (ca_file, ca_file_length, "%s/%s", ca_directory, dent->d_name);
              if (stat (ca_file, &st) != 0)
                continue;

              if (! S_ISREG (st.st_mode))
                continue;

              /* avoid loading the same file twice by checking the inode.  */
              if (hash_table_contains (inode_map, (void *)(intptr_t) st.st_ino))
                continue;

              hash_table_put (inode_map, (void *)(intptr_t) st.st_ino, NULL);
              if ((rc = gnutls_certificate_set_x509_trust_file (credentials, ca_file,
                                                                GNUTLS_X509_FMT_PEM)) <= 0)
                DEBUGP (("WARNING: Failed to open cert %s: (%d).\n", ca_file, rc));
              else
                ncerts += rc;
            }

          hash_table_destroy (inode_map);
          closedir (dir);
        }
    }

  if (opt.ca_cert)
    {
      int rc;

      ncerts = 0;

      if ((rc = gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
                                                        GNUTLS_X509_FMT_PEM)) <= 0)
        logprintf (LOG_NOTQUIET, _ ("ERROR: Failed to open cert %s: (%d).\n"),
                   opt.ca_cert, rc);
      else
        {
          ncerts += rc;
          logprintf (LOG_NOTQUIET, _ ("Loaded CA certificate '%s'\n"), opt.ca_cert);
        }
    }

  if (opt.crl_file)
    {
      int rc;

      if ((rc = gnutls_certificate_set_x509_crl_file (credentials, opt.crl_file, GNUTLS_X509_FMT_PEM)) <= 0)
        {
          logprintf (LOG_NOTQUIET, _("ERROR: Failed to load CRL file '%s': (%d)\n"), opt.crl_file, rc);
          return false;
        }

      logprintf (LOG_NOTQUIET, _ ("Loaded CRL file '%s'\n"), opt.crl_file);
    }

  DEBUGP (("Certificates loaded: %d\n", ncerts));

  /* Use the private key from the cert file unless otherwise specified. */
  if (opt.cert_file && !opt.private_key)
    {
      opt.private_key = xstrdup (opt.cert_file);
      opt.private_key_type = opt.cert_type;
    }
  /* Use the cert from the private key file unless otherwise specified. */
  if (!opt.cert_file && opt.private_key)
    {
      opt.cert_file = xstrdup (opt.private_key);
      opt.cert_type = opt.private_key_type;
    }

  if (opt.cert_file && opt.private_key)
    {
      int type;
      if (opt.private_key_type != opt.cert_type)
        {
          /* GnuTLS can't handle this */
          logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
cert to be of the same type.\n"));
        }
Esempio n. 17
0
static inline int
help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
	 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
	struct ip_ct_rtsp_expect expinfo;
	
	int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
	//struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
	//uint    tcplen = pktlen - iph->ihl * 4;
	char*   pdata = rb_ptr;
	//uint    datalen = tcplen - tcph->doff * 4;
	uint    dataoff = 0;
	int ret = NF_ACCEPT;
	
	struct nf_conntrack_expect *exp;
	
	__be16 be_loport;
	
	typeof(nf_nat_rtsp_hook) nf_nat_rtsp;

	memset(&expinfo, 0, sizeof(expinfo));
	
	while (dataoff < datalen) {
		uint    cmdoff = dataoff;
		uint    hdrsoff = 0;
		uint    hdrslen = 0;
		uint    cseqoff = 0;
		uint    cseqlen = 0;
		uint    transoff = 0;
		uint    translen = 0;
		
		if (!rtsp_parse_message(pdata, datalen, &dataoff,
					&hdrsoff, &hdrslen,
					&cseqoff, &cseqlen,
					&transoff, &translen))
			break;      /* not a valid message */
		
		if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
			continue;   /* not a SETUP message */
		DEBUGP("found a setup message\n");

		if (translen) {
			rtsp_parse_transport(pdata+transoff, translen, &expinfo);
		}

		if (expinfo.loport == 0) {
			DEBUGP("no udp transports found\n");
			continue;   /* no udp transports found */
		}

		DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
		       (int)expinfo.pbtype, expinfo.loport, expinfo.hiport);

		exp = nf_conntrack_expect_alloc(ct);
		if (!exp) {
			ret = NF_DROP;
			goto out;
		}

		be_loport = htons(expinfo.loport);

		nf_conntrack_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, ct->tuplehash[!dir].tuple.src.l3num,
			/* media stream source can be different from the RTSP server address
			&ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, */
			NULL, &ct->tuplehash[!dir].tuple.dst.u3,
			IPPROTO_UDP, NULL, &be_loport); 

		exp->master = ct;

		exp->expectfn = expected;
		exp->flags = 0;

		if (expinfo.pbtype == pb_range) {
			DEBUGP("Changing expectation mask to handle multiple ports\n");
			//exp->mask.dst.u.udp.port  = 0xfffe;
		}

		DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
		       NIPQUAD(exp->tuple.src.u3.ip),
		       ntohs(exp->tuple.src.u.udp.port),
		       NIPQUAD(exp->tuple.dst.u3.ip),
		       ntohs(exp->tuple.dst.u.udp.port));

		nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook);
		if (nf_nat_rtsp && ct->status & IPS_NAT_MASK)
			/* pass the request off to the nat helper */
			ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp);
		else if (nf_conntrack_expect_related(exp) != 0) {
			DEBUGP("nf_conntrack_expect_related failed\n");
			ret  = NF_DROP;
		}
		nf_conntrack_expect_put(exp);
		goto out;
	}
out:

	return ret;
}
static int help(struct sk_buff **pskb,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	unsigned int dataoff;
	struct tcphdr _tcph, *th;
	char *data, *data_limit, *ib_ptr;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack_expect *exp;
	u32 seq;
	u_int32_t dcc_ip;
	u_int16_t dcc_port;
	int i, ret = NF_ACCEPT;
	char *addr_beg_p, *addr_end_p;
	typeof(ip_nat_irc_hook) ip_nat_irc;

	DEBUGP("entered\n");

	/* If packet is coming from IRC server */
	if (dir == IP_CT_DIR_REPLY)
		return NF_ACCEPT;

	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not a full tcp header? */
	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
				sizeof(_tcph), &_tcph);
	if (th == NULL)
		return NF_ACCEPT;

	/* No data? */
	dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
	if (dataoff >= (*pskb)->len)
		return NF_ACCEPT;

	spin_lock_bh(&irc_buffer_lock);
	ib_ptr = skb_header_pointer(*pskb, dataoff,
				    (*pskb)->len - dataoff, irc_buffer);
	BUG_ON(ib_ptr == NULL);

	data = ib_ptr;
	data_limit = ib_ptr + (*pskb)->len - dataoff;

	/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
	 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
	while (data < (data_limit - (19 + MINMATCHLEN))) {
		if (memcmp(data, "\1DCC ", 5)) {
			data++;
			continue;
		}

		data += 5;
		/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */

		DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
			NIPQUAD(iph->saddr), ntohs(th->source),
			NIPQUAD(iph->daddr), ntohs(th->dest));

		for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
			if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
				/* no match */
				continue;
			}

			DEBUGP("DCC %s detected\n", dccprotos[i]);
			data += strlen(dccprotos[i]);
			/* we have at least
			 * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
			 * data left (== 14/13 bytes) */
			if (parse_dcc((char *)data, data_limit, &dcc_ip,
				       &dcc_port, &addr_beg_p, &addr_end_p)) {
				/* unable to parse */
				DEBUGP("unable to parse dcc command\n");
				continue;
			}
			DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
				HIPQUAD(dcc_ip), dcc_port);

			/* dcc_ip can be the internal OR external (NAT'ed) IP
			 * Tiago Sousa <[email protected]> */
			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
			    && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
				if (net_ratelimit())
					printk(KERN_WARNING
						"Forged DCC command from "
						"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
						HIPQUAD(dcc_ip), dcc_port);

				continue;
			}

			exp = ip_conntrack_expect_alloc(ct);
			if (exp == NULL) {
				ret = NF_DROP;
				goto out;
			}

			/* save position of address in dcc string,
			 * necessary for NAT */
			DEBUGP("tcph->seq = %u\n", th->seq);
			seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);

			/* We refer to the reverse direction ("!dir")
			 * tuples here, because we're expecting
			 * something in the other * direction.
			 * Doesn't matter unless NAT is happening.  */
			exp->tuple = ((struct ip_conntrack_tuple)
				{ { 0, { 0 } },
				  { ct->tuplehash[!dir].tuple.dst.ip,
				    { .tcp = { htons(dcc_port) } },
				    IPPROTO_TCP }});
Esempio n. 19
0
/* Process a command line option */
static void process_option(int opt, char *optarg, struct config *config,
			   char *where)
{
	int port = 0;
	char *end = NULL;
	unsigned long speed = 0;

	DEBUGP("process_option %d ('%c') = %s\n",
	       opt, (char)opt, optarg);

	switch (opt) {
	case OPT_IP_VERSION:
		if (strcmp(optarg, "ipv4") == 0)
			config->ip_version = IP_VERSION_4;
		else if (strcmp(optarg, "ipv4-mapped-ipv6") == 0)
			config->ip_version = IP_VERSION_4_MAPPED_6;
		else if (strcmp(optarg, "ipv6") == 0)
			config->ip_version = IP_VERSION_6;
		else
			die("%s: bad --ip_version: %s\n", where, optarg);
		break;
	case OPT_BIND_PORT:
		port = atoi(optarg);
		if ((port <= 0) || (port > 0xffff))
			die("%s: bad --bind_port: %s\n", where, optarg);
		//config->live_bind_port = port;
		config->default_live_bind_port = port;
		break;
	case OPT_CODE_COMMAND:
		config->code_command_line = optarg;
		break;
	case OPT_CODE_FORMAT:
		config->code_format = optarg;
		break;
	case OPT_CODE_SOCKOPT:
		config->code_sockopt = optarg;
		break;
	case OPT_CONNECT_PORT:
		port = atoi(optarg);
		if ((port <= 0) || (port > 0xffff))
			die("%s: bad --connect_port: %s\n", where, optarg);
		config->default_live_connect_port = port;
		break;
	case OPT_REMOTE_IP:
		strncpy(config->live_remote_ip_string, optarg, ADDR_STR_LEN-1);
		break;
	case OPT_LOCAL_IP:
		strncpy(config->live_local_ip_string, optarg, ADDR_STR_LEN-1);
		break;
	case OPT_GATEWAY_IP:
		strncpy(config->live_gateway_ip_string, optarg, ADDR_STR_LEN-1);
		break;
	case OPT_MTU:
		config->mtu = atoi(optarg);
		if (config->mtu < 0)
			die("%s: bad --mtu: %s\n", where, optarg);
		break;
	case OPT_NETMASK_IP:
		strncpy(config->live_netmask_ip_string, optarg,	ADDR_STR_LEN-1);
		break;
	case OPT_INIT_SCRIPTS:
		config->init_scripts = optarg;
		break;
	case OPT_NON_FATAL:
		parse_non_fatal_arg(optarg, config);
		break;
	case OPT_SPEED:
		speed = strtoul(optarg, &end, 10);
		if (end == optarg || *end || !is_valid_u32(speed))
			die("%s: bad --speed: %s\n", where, optarg);
		config->speed = speed;
		break;
	case OPT_TOLERANCE_USECS:
		config->tolerance_usecs = atoi(optarg);
		if (config->tolerance_usecs <= 0)
			die("%s: bad --tolerance_usecs: %s\n", where, optarg);
		break;
	case OPT_TCP_TS_TICK_USECS:
		config->tcp_ts_tick_usecs = atoi(optarg);
		if (config->tcp_ts_tick_usecs < 0 ||
		    config->tcp_ts_tick_usecs > 1000000)
			die("%s: bad --tcp_ts_tick_usecs: %s\n", where, optarg);
		break;
	case OPT_WIRE_CLIENT:
		config->is_wire_client = true;
		break;
	case OPT_WIRE_SERVER:
		config->is_wire_server = true;
		break;
	case OPT_WIRE_SERVER_IP:
		config->wire_server_ip_string = strdup(optarg);
		config->wire_server_ip	=
			ipv4_parse(config->wire_server_ip_string);
		break;
	case OPT_WIRE_SERVER_PORT:
		port = atoi(optarg);
		if ((port <= 0) || (port > 0xffff))
			die("%s: bad --wire_server_port: %s\n", where, optarg);
		config->wire_server_port = port;
		break;
	case OPT_WIRE_CLIENT_DEV:
		config->wire_client_device = strdup(optarg);
		break;
	case OPT_WIRE_SERVER_DEV:
		config->wire_server_device = strdup(optarg);
		break;
	case OPT_VERBOSE:
		config->verbose = true;
		break;
	default:
		show_usage();
		exit(EXIT_FAILURE);
	}
}
Esempio n. 20
0
static void ipt_ulog_packet(unsigned int hooknum,
			    const struct sk_buff *skb,
			    const struct net_device *in,
			    const struct net_device *out,
			    const struct ipt_ulog_info *loginfo,
			    const char *prefix)
{
	ulog_buff_t *ub;
	ulog_packet_msg_t *pm;
	size_t size, copy_len;
	struct nlmsghdr *nlh;

	/* ffs == find first bit set, necessary because userspace
	 * is already shifting groupnumber, but we need unshifted.
	 * ffs() returns [1..32], we need [0..31] */
	unsigned int groupnum = ffs(loginfo->nl_group) - 1;

	/* calculate the size of the skb needed */
	if ((loginfo->copy_range == 0) ||
	    (loginfo->copy_range > skb->len)) {
		copy_len = skb->len;
	} else {
		copy_len = loginfo->copy_range;
	}

	size = NLMSG_SPACE(sizeof(*pm) + copy_len);

	ub = &ulog_buffers[groupnum];
	
	LOCK_BH(&ulog_lock);

	if (!ub->skb) {
		if (!(ub->skb = ulog_alloc_skb(size)))
			goto alloc_failure;
	} else if (ub->qlen >= loginfo->qthreshold ||
		   size > skb_tailroom(ub->skb)) {
		/* either the queue len is too high or we don't have 
		 * enough room in nlskb left. send it to userspace. */

		ulog_send(groupnum);

		if (!(ub->skb = ulog_alloc_skb(size)))
			goto alloc_failure;
	}

	DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
		loginfo->qthreshold);

	/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
			sizeof(*pm)+copy_len);
	ub->qlen++;

	pm = NLMSG_DATA(nlh);

	/* We might not have a timestamp, get one */
	if (skb->stamp.tv_sec == 0)
		do_gettimeofday((struct timeval *)&skb->stamp);

	/* copy hook, prefix, timestamp, payload, etc. */
	pm->data_len = copy_len;
	pm->timestamp_sec = skb->stamp.tv_sec;
	pm->timestamp_usec = skb->stamp.tv_usec;
	pm->mark = skb->nfmark;
	pm->hook = hooknum;
	if (prefix != NULL)
		strncpy(pm->prefix, prefix, sizeof(pm->prefix));
	else if (loginfo->prefix[0] != '\0')
		strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
	else
		*(pm->prefix) = '\0';

	if (in && in->hard_header_len > 0
	    && skb->mac.raw != (void *) skb->nh.iph
	    && in->hard_header_len <= ULOG_MAC_LEN) {
		memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
		pm->mac_len = in->hard_header_len;
	} else
		pm->mac_len = 0;

	if (in)
		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
	else
		pm->indev_name[0] = '\0';

	if (out)
		strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
	else
		pm->outdev_name[0] = '\0';

	/* copy_len <= skb->len, so can't fail. */
	if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
		BUG();
	
	/* check if we are building multi-part messages */
	if (ub->qlen > 1) {
		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
	}

	ub->lastnlh = nlh;

	/* if timer isn't already running, start it */
	if (!timer_pending(&ub->timer)) {
		ub->timer.expires = jiffies + flushtimeout * HZ / 100;
		add_timer(&ub->timer);
	}

	/* if threshold is reached, send message to userspace */
	if (ub->qlen >= loginfo->qthreshold) {
		if (loginfo->qthreshold > 1)
			nlh->nlmsg_type = NLMSG_DONE;
		ulog_send(groupnum);
	}

	UNLOCK_BH(&ulog_lock);

	return;

nlmsg_failure:
	PRINTR("ipt_ULOG: error during NLMSG_PUT\n");

alloc_failure:
	PRINTR("ipt_ULOG: Error building netlink message\n");

	UNLOCK_BH(&ulog_lock);
}
Esempio n. 21
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      const void *protohdr,
      u_int16_t datalen,
      int *hotdrop)
{
       struct ipv6_rt_hdr *route = NULL;
       const struct ip6t_rt *rtinfo = matchinfo;
       unsigned int temp;
       unsigned int len;
       u8 nexthdr;
       unsigned int ptr;
       unsigned int hdrlen = 0;
       unsigned int ret = 0;

       /* type of the 1st exthdr */
       nexthdr = skb->nh.ipv6h->nexthdr;
       /* pointer to the 1st exthdr */
       ptr = sizeof(struct ipv6hdr);
       /* available length */
       len = skb->len - ptr;
       temp = 0;

        while (ipv6_ext_hdr(nexthdr)) {
               struct ipv6_opt_hdr *hdr;

              DEBUGP("ipv6_rt header iteration \n");

              /* Is there enough space for the next ext header? */
                if (len < (int)sizeof(struct ipv6_opt_hdr))
                        return 0;
              /* No more exthdr -> evaluate */
                if (nexthdr == NEXTHDR_NONE) {
                     break;
              }
              /* ESP -> evaluate */
                if (nexthdr == NEXTHDR_ESP) {
                     break;
              }

              hdr=skb->data+ptr;

              /* Calculate the header length */
                if (nexthdr == NEXTHDR_FRAGMENT) {
                        hdrlen = 8;
                } else if (nexthdr == NEXTHDR_AUTH)
                        hdrlen = (hdr->hdrlen+2)<<2;
                else
                        hdrlen = ipv6_optlen(hdr);

              /* ROUTING -> evaluate */
                if (nexthdr == NEXTHDR_ROUTING) {
                     temp |= MASK_ROUTING;
                     break;
              }


              /* set the flag */
              switch (nexthdr){
                     case NEXTHDR_HOP:
                     case NEXTHDR_ROUTING:
                     case NEXTHDR_FRAGMENT:
                     case NEXTHDR_AUTH:
                     case NEXTHDR_DEST:
                            break;
                     default:
                            DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_rt: new pointer is too large! \n");
			break;
		}
        }

       /* ROUTING header not found */
       if ( temp != MASK_ROUTING ) return 0;

       if (len < (int)sizeof(struct ipv6_rt_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

       if (len < hdrlen){
	       /* Pcket smaller than its length field */
       		return 0;
       }

       route=skb->data+ptr;

       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
       DEBUGP("TYPE %04X ", route->type);
       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));

       DEBUGP("IPv6 RT segsleft %02X ",
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           ntohl(route->segments_left),
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
       DEBUGP("type %02X %02X %02X ",
       		rtinfo->rt_type, route->type, 
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == route->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
       DEBUGP("len %02X %04X %02X ",
       		rtinfo->hdrlen, hdrlen,
       		(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
       DEBUGP("res %02X %02X %02X ", 
       		(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->reserved,
       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->reserved)));

       ret = (route != NULL)
       		&&
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           ntohl(route->segments_left),
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
		&&
	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
		&&
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == route->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)))
		&&
       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->reserved));

	DEBUGP("#%d ",rtinfo->addrnr);
       temp = len = ptr = 0;
       if ( !(rtinfo->flags & IP6T_RT_FST) ){
	       return ret;
	} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
		DEBUGP("Not strict ");
		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
			DEBUGP("There isn't enough space\n");
			return 0;
		} else {
			DEBUGP("#%d ",rtinfo->addrnr);
			ptr = 0;
			for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
				len = 0;
				while ((u8)(((struct rt0_hdr *)route)->
						addr[temp].s6_addr[len]) ==
					(u8)(rtinfo->addrs[ptr].s6_addr[len])){
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
					len++;
					if ( len == 16 ) break;
				}
				if (len==16) {
					DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
					ptr++;
				} else {
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
					DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
				}
				if (ptr==rtinfo->addrnr) break;
			}
			DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
			if ( (len == 16) && (ptr == rtinfo->addrnr))
				return ret;
			else return 0;
		}
	} else {
		DEBUGP("Strict ");
		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
			DEBUGP("There isn't enough space\n");
			return 0;
		} else {
			DEBUGP("#%d ",rtinfo->addrnr);
			for(temp=0; temp<rtinfo->addrnr; temp++){
				len = 0;
				while ((u8)(((struct rt0_hdr *)route)->
						addr[temp].s6_addr[len]) ==
					(u8)(rtinfo->addrs[temp].s6_addr[len])){
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[temp].s6_addr[len]));
					len++;
					if ( len == 16 ) break;
				}
				if (len!=16) {
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[temp].s6_addr[len]));
					DEBUGP("!len=%d temp=%d;\n",len,temp);
					break;
				}
			}
			DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
			if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
				return ret;
			else return 0;
		}
	}

	return 0;
}
Esempio n. 22
0
static void ipt_logfn(unsigned int hooknum,
		      const struct sk_buff *skb,
		      const struct net_device *in,
		      const struct net_device *out,
		      const char *prefix)
{
	struct ipt_ulog_info loginfo = { 
		.nl_group = ULOG_DEFAULT_NLGROUP,
		.copy_range = 0,
		.qthreshold = ULOG_DEFAULT_QTHRESHOLD,
		.prefix = ""
	};

	ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
}

static int ipt_ulog_checkentry(const char *tablename,
			       const struct ipt_entry *e,
			       void *targinfo,
			       unsigned int targinfosize,
			       unsigned int hookmask)
{
	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;

	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
		DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
		return 0;
	}

	if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
		DEBUGP("ipt_ULOG: prefix term %i\n",
		       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
		return 0;
	}

	if (loginfo->qthreshold > ULOG_MAX_QLEN) {
		DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
			loginfo->qthreshold);
		return 0;
	}

	return 1;
}

static struct ipt_target ipt_ulog_reg = {
	.name		= "ULOG",
	.target		= ipt_ulog_target,
	.checkentry	= ipt_ulog_checkentry,
	.me		= THIS_MODULE,
};

static int __init init(void)
{
	int i;

	DEBUGP("ipt_ULOG: init module\n");

	if (nlbufsiz >= 128*1024) {
		printk("Netlink buffer has to be <= 128kB\n");
		return -EINVAL;
	}

	/* initialize ulog_buffers */
	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
		init_timer(&ulog_buffers[i].timer);
		ulog_buffers[i].timer.function = ulog_timer;
		ulog_buffers[i].timer.data = i;
	}

	nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
	if (!nflognl)
		return -ENOMEM;

	if (ipt_register_target(&ipt_ulog_reg) != 0) {
		sock_release(nflognl->sk_socket);
		return -EINVAL;
	}
	if (nflog)
		nf_log_register(PF_INET, &ipt_logfn);
	
	return 0;
}

static void __exit fini(void)
{
	ulog_buff_t *ub;
	int i;

	DEBUGP("ipt_ULOG: cleanup_module\n");

	if (nflog)
		nf_log_unregister(PF_INET, &ipt_logfn);
	ipt_unregister_target(&ipt_ulog_reg);
	sock_release(nflognl->sk_socket);

	/* remove pending timers and free allocated skb's */
	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
		ub = &ulog_buffers[i];
		if (timer_pending(&ub->timer)) {
			DEBUGP("timer was pending, deleting\n");
			del_timer(&ub->timer);
		}

		if (ub->skb) {
			kfree_skb(ub->skb);
			ub->skb = NULL;
		}
	}

}
Esempio n. 23
0
static inline int 
pptp_inbound_pkt(struct tcphdr *tcph,
		 struct pptp_pkt_hdr *pptph, 
		 size_t datalen,
		 struct ip_conntrack *ct,
		 enum ip_conntrack_info ctinfo)
{
	struct PptpControlHeader *ctlh;
        union pptp_ctrl_union pptpReq;
	
	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
	u_int16_t msg, *cid, *pcid;
	u_int32_t seq;	

	ctlh = (struct PptpControlHeader *) 
		((char *) pptph + sizeof(struct pptp_pkt_hdr));
	pptpReq.rawreq = (void *) 
		((char *) ctlh + sizeof(struct PptpControlHeader));

	msg = ntohs(ctlh->messageType);
	DEBUGP("inbound control message %s\n", strMName[msg]);

	switch (msg) {
	case PPTP_START_SESSION_REPLY:
		/* server confirms new control session */
		if (info->sstate < PPTP_SESSION_REQUESTED) {
			DEBUGP("%s without START_SESS_REQUEST\n",
				strMName[msg]);
			break;
		}
		if (pptpReq.srep->resultCode == PPTP_START_OK)
			info->sstate = PPTP_SESSION_CONFIRMED;
		else 
			info->sstate = PPTP_SESSION_ERROR;
		break;

	case PPTP_STOP_SESSION_REPLY:
		/* server confirms end of control session */
		if (info->sstate > PPTP_SESSION_STOPREQ) {
			DEBUGP("%s without STOP_SESS_REQUEST\n",
				strMName[msg]);
			break;
		}
		if (pptpReq.strep->resultCode == PPTP_STOP_OK)
			info->sstate = PPTP_SESSION_NONE;
		else
			info->sstate = PPTP_SESSION_ERROR;
		break;

	case PPTP_OUT_CALL_REPLY:
		/* server accepted call, we now expect GRE frames */
		if (info->sstate != PPTP_SESSION_CONFIRMED) {
			DEBUGP("%s but no session\n", strMName[msg]);
			break;
		}
		if (info->cstate != PPTP_CALL_OUT_REQ &&
		    info->cstate != PPTP_CALL_OUT_CONF) {
			DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
			break;
		}
		if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
			info->cstate = PPTP_CALL_NONE;
			break;
		}

		cid = &pptpReq.ocack->callID;
		pcid = &pptpReq.ocack->peersCallID;

		info->pac_call_id = ntohs(*cid);
		
		if (htons(info->pns_call_id) != *pcid) {
			DEBUGP("%s for unknown callid %u\n",
				strMName[msg], ntohs(*pcid));
			break;
		}

		DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], 
			ntohs(*cid), ntohs(*pcid));
		
		info->cstate = PPTP_CALL_OUT_CONF;

		seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
		if (exp_gre(ct, seq, *cid, *pcid) != 0)
			printk("ip_conntrack_pptp: error during exp_gre\n");
		break;

	case PPTP_IN_CALL_REQUEST:
		/* server tells us about incoming call request */
		if (info->sstate != PPTP_SESSION_CONFIRMED) {
			DEBUGP("%s but no session\n", strMName[msg]);
			break;
		}
		pcid = &pptpReq.icack->peersCallID;
		DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
		info->cstate = PPTP_CALL_IN_REQ;
		info->pac_call_id= ntohs(*pcid);
		break;

	case PPTP_IN_CALL_CONNECT:
		/* server tells us about incoming call established */
		if (info->sstate != PPTP_SESSION_CONFIRMED) {
			DEBUGP("%s but no session\n", strMName[msg]);
			break;
		}
		if (info->sstate != PPTP_CALL_IN_REP
		    && info->sstate != PPTP_CALL_IN_CONF) {
			DEBUGP("%s but never sent IN_CALL_REPLY\n",
				strMName[msg]);
			break;
		}

		pcid = &pptpReq.iccon->peersCallID;
		cid = &info->pac_call_id;

		if (info->pns_call_id != ntohs(*pcid)) {
			DEBUGP("%s for unknown CallID %u\n", 
				strMName[msg], ntohs(*cid));
			break;
		}

		DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
		info->cstate = PPTP_CALL_IN_CONF;

		/* we expect a GRE connection from PAC to PNS */
		seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
		if (exp_gre(ct, seq, *cid, *pcid) != 0)
			printk("ip_conntrack_pptp: error during exp_gre\n");

		break;

	case PPTP_CALL_DISCONNECT_NOTIFY:
		/* server confirms disconnect */
		cid = &pptpReq.disc->callID;
		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
		info->cstate = PPTP_CALL_NONE;

		/* untrack this call id, unexpect GRE packets */
		pptp_timeout_related(ct, ctinfo);
		break;

	case PPTP_WAN_ERROR_NOTIFY:
		break;

	case PPTP_ECHO_REQUEST:
	case PPTP_ECHO_REPLY:
		/* I don't have to explain these ;) */
		break;
	default:
		DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
			? strMName[msg]:strMName[0], msg);
		break;
	}

	return NF_ACCEPT;

}
Esempio n. 24
0
static int llparse_byte(struct llparser *llp, char byte)
{
	int ret = 0;

	switch (llp->state) {
	case LLPARSE_STATE_IDLE:
	case LLPARSE_STATE_PROMPT_SPC:
		if (llp->flags & LGSM_ATCMD_F_EXTENDED) {
			if (byte == '\n')
				break;
			else if (byte == '\r')
				llp->state = LLPARSE_STATE_IDLE_CR;
			else if (byte == '>')
				llp->state = LLPARSE_STATE_PROMPT;
			else {
#ifdef STRICT
				llp->state = LLPARSE_STATE_ERROR;
#else
				llp->state = LLPARSE_STATE_RESULT;
				ret = llparse_append(llp, byte);
#endif
			}
		} else {
			llp->state = LLPARSE_STATE_RESULT;
			ret = llparse_append(llp, byte);
		}
		break;
	case LLPARSE_STATE_IDLE_CR:
		if (byte == '\n')
			llp->state = LLPARSE_STATE_IDLE_LF;
		else
			llp->state = LLPARSE_STATE_ERROR;
		break;
	case LLPARSE_STATE_IDLE_LF:
		if (byte == '\r') {
			/* can we really go directly into result_cr ? */
			DEBUGP("** IDLE_LF -> RESULT_CR? **\n");
			llp->state = LLPARSE_STATE_RESULT_CR;
		} else if (byte == '>') {
			llp->state = LLPARSE_STATE_PROMPT;
		} else {
			llp->state = LLPARSE_STATE_RESULT;
			ret = llparse_append(llp, byte);
		}
		break;
	case LLPARSE_STATE_RESULT:
		if (byte == '\r') {
			llp->state = LLPARSE_STATE_RESULT_CR;
		} else if ((llp->flags & LGSM_ATCMD_F_LFCR) && byte == '\n') {
			llp->state = LLPARSE_STATE_RESULT_LF;
		} else if ((llp->flags & LGSM_ATCMD_F_LFLF) && byte == '\n') {
			llp->state = LLPARSE_STATE_RESULT_CR;
		} else {
			if (byte == '"') 
				llp->state = LLPARSE_STATE_QUOTE;
			ret = llparse_append(llp, byte);
		}
		break;
	case LLPARSE_STATE_QUOTE:
		/* We allow line feeds (\n) in quote enclosed strings */
		if (byte == '"') {
			/* Potentially the end quote */
			llp->state = LLPARSE_STATE_RESULT;
		} else if (byte == '\r') {
			llp->state = LLPARSE_STATE_RESULT_CR;
			break;
		}
		ret = llparse_append(llp, byte);
		break;
	case LLPARSE_STATE_RESULT_CR:
		if (byte == '\n') {
			llparse_endline(llp);
		}
		break;
	case LLPARSE_STATE_RESULT_LF:
		if (byte == '\r') {
			llparse_endline(llp);
		}
		break;
	case LLPARSE_STATE_PROMPT:
		if (byte == ' ')
			llp->state = LLPARSE_STATE_PROMPT_SPC;
		else {
			/* this was not a real "> " prompt */
			llparse_append(llp, '>');
			ret = llparse_append(llp, byte);
			llp->state = LLPARSE_STATE_RESULT;
		}
		break;
	case LLPARSE_STATE_ERROR:
		break;
	}

	return ret;
}
Esempio n. 25
0
/* track caller id inside control connection, call expect_related */
static int 
conntrack_pptp_help(const struct iphdr *iph, size_t len,
		    struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)

{
	struct pptp_pkt_hdr *pptph;
	
	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
	u_int32_t tcplen = len - iph->ihl * 4;
	u_int32_t datalen = tcplen - tcph->doff * 4;
	void *datalimit;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;

	int oldsstate, oldcstate;
	int ret;

	/* don't do any tracking before tcp handshake complete */
	if (ctinfo != IP_CT_ESTABLISHED 
	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
		DEBUGP("ctinfo = %u, skipping\n", ctinfo);
		return NF_ACCEPT;
	}
	
	/* not a complete TCP header? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
		DEBUGP("tcplen = %u\n", tcplen);
		return NF_ACCEPT;
	}

	/* checksum invalid? */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			csum_partial((char *) tcph, tcplen, 0))) {
		printk(KERN_NOTICE __FILE__ ": bad csum\n");
		/* W2K PPTP server sends TCP packets with wrong checksum :(( */
		//return NF_ACCEPT;
	}

	if (tcph->fin || tcph->rst) {
		DEBUGP("RST/FIN received, timeouting GRE\n");
		/* can't do this after real newnat */
		info->cstate = PPTP_CALL_NONE;

		/* untrack this call id, unexpect GRE packets */
		pptp_timeout_related(ct, ctinfo);
	}


	pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
	datalimit = (void *) pptph + datalen;

	/* not a full pptp packet header? */
	if ((void *) pptph+sizeof(*pptph) >= datalimit) {
		DEBUGP("no full PPTP header, can't track\n");
		return NF_ACCEPT;
	}
	
	/* if it's not a control message we can't do anything with it */
        if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
		DEBUGP("not a control packet\n");
		return NF_ACCEPT;
	}

	oldsstate = info->sstate;
	oldcstate = info->cstate;

	LOCK_BH(&ip_pptp_lock);

	/* FIXME: We just blindly assume that the control connection is always
	 * established from PNS->PAC.  However, RFC makes no guarantee */
	if (dir == IP_CT_DIR_ORIGINAL)
		/* client -> server (PNS -> PAC) */
		ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
	else
		/* server -> client (PAC -> PNS) */
		ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
	DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
		oldsstate, info->sstate, oldcstate, info->cstate);
	UNLOCK_BH(&ip_pptp_lock);

	return ret;
}
Esempio n. 26
0
static int atcmd_done(struct gsmd *g, struct gsmd_atcmd *cmd,
	const char *buf, u_int8_t channel)
{
	int rc = 0;
#if ENABLE_TIMEOUTS
	remove_channel_timeout(g, channel);
#endif
	if (!cmd) {
		gsmd_log(GSMD_ERROR, "* Null cmd? *\n");
		return -1;
	}

	if (!cmd->cb) {
		gsmd_log(GSMD_NOTICE, "command without cb!!!\n");
	} else {
		cmd->flags = ATCMD_FINAL_CB_FLAG;
		/* send final result code if there is no information
		 * response in mlbuf */
		if (g->mlbuf_len[channel]) {
			cmd->resp = g->mlbuf[channel];
			cmd->resplen = g->mlbuf_len[channel];
			cmd->resp[cmd->resplen] = 0;
		} else {
			cmd->resp = (char*) buf;
			cmd->resplen = strlen(buf);
		}
		DEBUGP("Calling final cmd->cb() %d <%s>(%d) <%d>\n",
			g->mlbuf_len[channel],cmd->resp,cmd->resplen,cmd->ret);
		rc = cmd->cb(cmd, cmd->ctx, cmd->resp);
		if (rc < 0) {
			gsmd_log(GSMD_ERROR, "Failed to create response for client\n");
		}
		DEBUGP("Clearing mlbuf\n");
		g->mlbuf_len[channel] = 0;
		g->mlbuf[channel][0] = 0;
	}

	/* remove from list of currently executing cmds */
	llist_del(&cmd->list);
#if ENABLE_TIMEOUTS
	if (TIMEOUT_ERRORCODE == cmd->ret && STATUS_OK == g->modem_status)
		check_channel(g,channel);
#endif
	atcmd_free(cmd);

	/* We're finished with the current command, but if still have pending
	* command(s) then pop off the first pending */
	if (llist_empty(&g->busy_atcmds[channel])) {
		struct gsmd_atcmd *cur = NULL;
		u_int32_t initial_delay_secs = 0;
		if (!llist_empty(&g->pending_atcmds[channel])) {
			gsmd_log(GSMD_INFO, "cmds pending\n");
			cur = llist_entry(g->pending_atcmds[channel].next,
				struct gsmd_atcmd, list);
			if (cur) {
				initial_delay_secs = cur->initial_delay_secs;
			} else {
				gsmd_log(GSMD_ERROR, "First pending is null?\n");
			}
		}
		if (g->pin_status) {
			if (cur) {
				if (cur->flags & ATCMD_PIN_SENSITIVE) {
					gsmd_log(GSMD_INFO, "pin_status %d\n",g->pin_status);
					if (g->sim_status == GSM0707_CME_SIM_NOT_INSERTED) {
						gsmd_log(GSMD_INFO, "sim not inserted\n");
						/* allow the modem to fail the cmd */
						wake_pending_after_delay(
							g,channel,initial_delay_secs);
					} else {
						gsmd_log(GSMD_INFO, "* pin sensitive cmd delayed *\n");
						g->pin_sensitive_cmds_waiting = 1;
					}
				} else {
					gsmd_log(GSMD_INFO, "wake pending after %d\n", initial_delay_secs);
					wake_pending_after_delay(g,channel,initial_delay_secs);
				}
			}
		} else {
			if (g->pin_sensitive_cmds_waiting) {
				if (cur && (cur->flags & ATCMD_PIN_SENSITIVE)) {
					u_int8_t ch_iter = 0;
					gsmd_log(GSMD_INFO, "chk chnls for pin delayed cmds\n");
					for (ch_iter = 0; ch_iter < g->number_channels; ch_iter++) {
						if (ch_iter == channel)
							continue;
						if (!llist_empty(&g->pending_atcmds[ch_iter])) {
							struct gsmd_atcmd *cur2 =
								llist_entry(g->pending_atcmds[ch_iter].next,
									struct gsmd_atcmd, list);
							if (cur2 && (cur2->flags & ATCMD_PIN_SENSITIVE)) {
								gsmd_log(GSMD_INFO, "* waking chnl %d *\n",
									ch_iter);
								wake_pending_after_delay(
									g, ch_iter, initial_delay_secs);
							}
						}
					}
					g->pin_sensitive_cmds_waiting = 0;
				}
			}

			gsmd_log(GSMD_INFO, "wake pending after %d secs\n", initial_delay_secs);
			wake_pending_after_delay(g, channel,initial_delay_secs);
		}
Esempio n. 27
0
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & __constant_htons(IP_MF|IP_OFFSET)));

	(*pskb)->nfcache |= NFC_UNKNOWN;

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		(*pskb)->ip_summed = CHECKSUM_NONE;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
		struct iphdr *iph = (*pskb)->nh.iph;
		struct icmphdr *hdr = (struct icmphdr *)
			((u_int32_t *)iph + iph->ihl);
		if (iph->protocol == IPPROTO_ICMP
		    && hdr->type == ICMP_REDIRECT)
			return NF_DROP;
		return NF_ACCEPT;
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			return icmp_reply_translation(*pskb, ct, hooknum,
						      CTINFO2DIR(ctinfo));
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
		info = &ct->nat.info;

		WRITE_LOCK(&ip_nat_lock);
		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!(info->initialized & (1 << maniptype))) {
			int in_hashes = info->initialized;
			unsigned int ret;

			ret = ip_nat_rule_find(pskb, hooknum, in, out,
					       ct, info);
			if (ret != NF_ACCEPT) {
				WRITE_UNLOCK(&ip_nat_lock);
				return ret;
			}

			if (in_hashes) {
				IP_NF_ASSERT(info->bysource.conntrack);
				replace_in_hashes(ct, info);
			} else {
				place_in_hashes(ct, info);
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		WRITE_UNLOCK(&ip_nat_lock);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return do_bindings(ct, ctinfo, info, hooknum, pskb);
}
Esempio n. 28
0
struct address_list *
lookup_host (const char *host, int silent)
{
  struct address_list *al = NULL;
  unsigned long addr;
  struct hostent *hptr;

  /* If the address is of the form d.d.d.d, no further lookup is
     needed.  */
  addr = (unsigned long)inet_addr (host);
  if ((int)addr != -1)
    {
      /* ADDR is defined to be in network byte order, which is what
	 this returns, so we can just copy it to STORE_IP.  However,
	 on big endian 64-bit architectures the value will be stored
	 in the *last*, not first four bytes.  OFFSET makes sure that
	 we copy the correct four bytes.  */
      int offset;
#ifdef WORDS_BIGENDIAN
      offset = sizeof (unsigned long) - IP4_ADDRESS_LENGTH;
#else
      offset = 0;
#endif
      return address_list_new_one ((char *)&addr + offset);
    }

  /* By now we know that the host name we got is not of the form
     d.d.d.d.  Try to find it in our cache of host names.  */
  if (host_name_addresses_map)
    al = hash_table_get (host_name_addresses_map, host);

  if (al)
    {
      DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
      ++al->refcount;
      return al;
    }

  if (!silent)
    logprintf (LOG_VERBOSE, _("Resolving %s... "), host);

  /* Look up the host using gethostbyname().  */
  hptr = gethostbyname (host);
  if (!hptr)
    {
      if (!silent)
	logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
      return NULL;
    }

  if (!silent)
    logprintf (LOG_VERBOSE, _("done.\n"));

  /* Do all systems have h_addr_list, or is it a newer thing?  If the
     latter, use address_list_new_one.  */
  al = address_list_new (hptr->h_addr_list);

  /* Cache the lookup information. */
  cache_host_lookup (host, al);

  return al;
}
Esempio n. 29
0
uerr_t
retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
              char **newloc, const char *refurl, int *dt, bool recursive,
              struct iri *iri, bool register_status)
{
    uerr_t result;
    char *url;
    bool location_changed;
    bool iri_fallbacked = 0;
    int dummy;
    char *mynewloc, *proxy;
    struct url *u = orig_parsed, *proxy_url;
    int up_error_code;            /* url parse error code */
    char *local_file;
    int redirection_count = 0;

    bool post_data_suspended = false;
    char *saved_post_data = NULL;
    char *saved_method = NULL;
    char *saved_post_file_name = NULL;

    /* If dt is NULL, use local storage.  */
    if (!dt)
    {
        dt = &dummy;
        dummy = 0;
    }
    url = xstrdup (origurl);
    if (newloc)
        *newloc = NULL;
    if (file)
        *file = NULL;

    if (!refurl)
        refurl = opt.referer;

redirected:
    /* (also for IRI fallbacking) */

    result = NOCONERROR;
    mynewloc = NULL;
    local_file = NULL;
    proxy_url = NULL;

    proxy = getproxy (u);
    if (proxy)
    {
        struct iri *pi = iri_new ();
        set_uri_encoding (pi, opt.locale, true);
        pi->utf8_encode = false;

        /* Parse the proxy URL.  */
        proxy_url = url_parse (proxy, &up_error_code, NULL, true);
        if (!proxy_url)
        {
            char *error = url_error (proxy, up_error_code);
            logprintf (LOG_NOTQUIET, _("Error parsing proxy URL %s: %s.\n"),
                       proxy, error);
            xfree (url);
            xfree (error);
            RESTORE_POST_DATA;
            result = PROXERR;
            goto bail;
        }
        if (proxy_url->scheme != SCHEME_HTTP && proxy_url->scheme != u->scheme)
        {
            logprintf (LOG_NOTQUIET, _("Error in proxy URL %s: Must be HTTP.\n"), proxy);
            url_free (proxy_url);
            xfree (url);
            RESTORE_POST_DATA;
            result = PROXERR;
            goto bail;
        }
    }

    if (u->scheme == SCHEME_HTTP
#ifdef HAVE_SSL
            || u->scheme == SCHEME_HTTPS
#endif
            || (proxy_url && proxy_url->scheme == SCHEME_HTTP))
    {
        result = http_loop (u, orig_parsed, &mynewloc, &local_file, refurl, dt,
                            proxy_url, iri);
    }
    else if (u->scheme == SCHEME_FTP)
    {
        /* If this is a redirection, temporarily turn off opt.ftp_glob
           and opt.recursive, both being undesirable when following
           redirects.  */
        bool oldrec = recursive, glob = opt.ftp_glob;
        if (redirection_count)
            oldrec = glob = false;

        result = ftp_loop (u, &local_file, dt, proxy_url, recursive, glob);
        recursive = oldrec;

        /* There is a possibility of having HTTP being redirected to
           FTP.  In these cases we must decide whether the text is HTML
           according to the suffix.  The HTML suffixes are `.html',
           `.htm' and a few others, case-insensitive.  */
        if (redirection_count && local_file && u->scheme == SCHEME_FTP)
        {
            if (has_html_suffix_p (local_file))
                *dt |= TEXTHTML;
        }
    }

    if (proxy_url)
    {
        url_free (proxy_url);
        proxy_url = NULL;
    }

    location_changed = (result == NEWLOCATION || result == NEWLOCATION_KEEP_POST);
    if (location_changed)
    {
        char *construced_newloc;
        struct url *newloc_parsed;

        assert (mynewloc != NULL);

        if (local_file)
            xfree (local_file);

        /* The HTTP specs only allow absolute URLs to appear in
           redirects, but a ton of boneheaded webservers and CGIs out
           there break the rules and use relative URLs, and popular
           browsers are lenient about this, so wget should be too. */
        construced_newloc = uri_merge (url, mynewloc);
        xfree (mynewloc);
        mynewloc = construced_newloc;

        /* Reset UTF-8 encoding state, keep the URI encoding and reset
           the content encoding. */
        iri->utf8_encode = opt.enable_iri;
        set_content_encoding (iri, NULL);
        xfree_null (iri->orig_url);
        iri->orig_url = NULL;

        /* Now, see if this new location makes sense. */
        newloc_parsed = url_parse (mynewloc, &up_error_code, iri, true);
        if (!newloc_parsed)
        {
            char *error = url_error (mynewloc, up_error_code);
            logprintf (LOG_NOTQUIET, "%s: %s.\n", escnonprint_uri (mynewloc),
                       error);
            if (orig_parsed != u)
            {
                url_free (u);
            }
            xfree (url);
            xfree (mynewloc);
            xfree (error);
            RESTORE_POST_DATA;
            goto bail;
        }

        /* Now mynewloc will become newloc_parsed->url, because if the
           Location contained relative paths like .././something, we
           don't want that propagating as url.  */
        xfree (mynewloc);
        mynewloc = xstrdup (newloc_parsed->url);

        /* Check for max. number of redirections.  */
        if (++redirection_count > opt.max_redirect)
        {
            logprintf (LOG_NOTQUIET, _("%d redirections exceeded.\n"),
                       opt.max_redirect);
            url_free (newloc_parsed);
            if (orig_parsed != u)
            {
                url_free (u);
            }
            xfree (url);
            xfree (mynewloc);
            RESTORE_POST_DATA;
            result = WRONGCODE;
            goto bail;
        }

        xfree (url);
        url = mynewloc;
        if (orig_parsed != u)
        {
            url_free (u);
        }
        u = newloc_parsed;

        /* If we're being redirected from POST, and we received a
           redirect code different than 307, we don't want to POST
           again.  Many requests answer POST with a redirection to an
           index page; that redirection is clearly a GET.  We "suspend"
           POST data for the duration of the redirections, and restore
           it when we're done.

        RFC2616 HTTP/1.1 introduces code 307 Temporary Redirect
         specifically to preserve the method of the request.
         */
        if (result != NEWLOCATION_KEEP_POST && !post_data_suspended)
            SUSPEND_POST_DATA;

        goto redirected;
    }

    /* Try to not encode in UTF-8 if fetching failed */
    if (!(*dt & RETROKF) && iri->utf8_encode)
    {
        iri->utf8_encode = false;
        if (orig_parsed != u)
        {
            url_free (u);
        }
        u = url_parse (origurl, NULL, iri, true);
        if (u)
        {
            DEBUGP (("[IRI fallbacking to non-utf8 for %s\n", quote (url)));
            url = xstrdup (u->url);
            iri_fallbacked = 1;
            goto redirected;
        }
        else
            DEBUGP (("[Couldn't fallback to non-utf8 for %s\n", quote (url)));
    }

    if (local_file && u && *dt & RETROKF)
    {
        register_download (u->url, local_file);

        if (!opt.spider && redirection_count && 0 != strcmp (origurl, u->url))
            register_redirection (origurl, u->url);

        if (*dt & TEXTHTML)
            register_html (local_file);

        if (*dt & TEXTCSS)
            register_css (local_file);
    }

    if (file)
        *file = local_file ? local_file : NULL;
    else
        xfree_null (local_file);

    if (orig_parsed != u)
    {
        url_free (u);
    }

    if (redirection_count || iri_fallbacked)
    {
        if (newloc)
            *newloc = url;
        else
            xfree (url);
    }
    else
    {
        if (newloc)
            *newloc = NULL;
        xfree (url);
    }

    RESTORE_POST_DATA;

bail:
    if (register_status)
        inform_exit_status (result);
    return result;
}
Esempio n. 30
0
int
main(int argc, char *argv[])
#endif
{
	iptc_handle_t handle = NULL;
	char buffer[10240];
	int c;
	char curtable[IPT_TABLE_MAXNAMELEN + 1];
	FILE *in;
	const char *modprobe = 0;
	int in_table = 0, testing = 0;

	program_name = "iptables-restore";
	program_version = IPTABLES_VERSION;
	line = 0;

	lib_dir = getenv("IPTABLES_LIB_DIR");
	if (!lib_dir)
		lib_dir = IPT_LIB_DIR;

#ifdef NO_SHARED_LIBS
	init_extensions();
#endif

	while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) {
		switch (c) {
			case 'b':
				binary = 1;
				break;
			case 'c':
				counters = 1;
				break;
			case 'v':
				verbose = 1;
				break;
			case 't':
				testing = 1;
				break;
			case 'h':
				print_usage("iptables-restore",
					    IPTABLES_VERSION);
				break;
			case 'n':
				noflush = 1;
				break;
			case 'M':
				modprobe = optarg;
				break;
		}
	}
	
	if (optind == argc - 1) {
		in = fopen(argv[optind], "r");
		if (!in) {
			fprintf(stderr, "Can't open %s: %s\n", argv[optind],
				strerror(errno));
			exit(1);
		}
	}
	else if (optind < argc) {
		fprintf(stderr, "Unknown arguments found on commandline\n");
		exit(1);
	}
	else in = stdin;
	
	/* Grab standard input. */
	while (fgets(buffer, sizeof(buffer), in)) {
		int ret = 0;

		line++;
		if (buffer[0] == '\n')
			continue;
		else if (buffer[0] == '#') {
			if (verbose)
				fputs(buffer, stdout);
			continue;
		} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
			if (!testing) {
				DEBUGP("Calling commit\n");
				ret = iptc_commit(&handle);
			} else {
				DEBUGP("Not calling commit, testing\n");
				ret = 1;
			}
			in_table = 0;
		} else if ((buffer[0] == '*') && (!in_table)) {
			/* New table */
			char *table;

			table = strtok(buffer+1, " \t\n");
			DEBUGP("line %u, table '%s'\n", line, table);
			if (!table) {
				exit_error(PARAMETER_PROBLEM, 
					"%s: line %u table name invalid\n",
					program_name, line);
				exit(1);
			}
			strncpy(curtable, table, IPT_TABLE_MAXNAMELEN);
			curtable[IPT_TABLE_MAXNAMELEN] = '\0';

			if (handle)
				iptc_free(&handle);

			handle = create_handle(table, modprobe);
			if (noflush == 0) {
				DEBUGP("Cleaning all chains of table '%s'\n",
					table);
				for_each_chain(flush_entries, verbose, 1, 
						&handle);
	
				DEBUGP("Deleting all user-defined chains "
				       "of table '%s'\n", table);
				for_each_chain(delete_chain, verbose, 0, 
						&handle) ;
			}

			ret = 1;
			in_table = 1;

		} else if ((buffer[0] == ':') && (in_table)) {
			/* New chain. */
			char *policy, *chain;

			chain = strtok(buffer+1, " \t\n");
			DEBUGP("line %u, chain '%s'\n", line, chain);
			if (!chain) {
				exit_error(PARAMETER_PROBLEM,
					   "%s: line %u chain name invalid\n",
					   program_name, line);
				exit(1);
			}

			if (iptc_builtin(chain, handle) <= 0) {
				if (noflush && iptc_is_chain(chain, handle)) {
					DEBUGP("Flushing existing user defined chain '%s'\n", chain);
					if (!iptc_flush_entries(chain, &handle))
						exit_error(PARAMETER_PROBLEM,
							   "error flushing chain "
							   "'%s':%s\n", chain,
							   strerror(errno));
				} else {
					DEBUGP("Creating new chain '%s'\n", chain);
					if (!iptc_create_chain(chain, &handle))
						exit_error(PARAMETER_PROBLEM,
							   "error creating chain "
							   "'%s':%s\n", chain,
							   strerror(errno));
				}
			}

			policy = strtok(NULL, " \t\n");
			DEBUGP("line %u, policy '%s'\n", line, policy);
			if (!policy) {
				exit_error(PARAMETER_PROBLEM,
					   "%s: line %u policy invalid\n",
					   program_name, line);
				exit(1);
			}

			if (strcmp(policy, "-") != 0) {
				struct ipt_counters count;

				if (counters) {
					char *ctrs;
					ctrs = strtok(NULL, " \t\n");

					if (!ctrs || !parse_counters(ctrs, &count))
						exit_error(PARAMETER_PROBLEM,
							   "invalid policy counters "
							   "for chain '%s'\n", chain);

				} else {
					memset(&count, 0, 
					       sizeof(struct ipt_counters));
				}

				DEBUGP("Setting policy of chain %s to %s\n",
					chain, policy);

				if (!iptc_set_policy(chain, policy, &count,
						     &handle))
					exit_error(OTHER_PROBLEM,
						"Can't set policy `%s'"
						" on `%s' line %u: %s\n",
						chain, policy, line,
						iptc_strerror(errno));
			}

			ret = 1;

		} else if (in_table) {
			int a;
			char *ptr = buffer;
			char *pcnt = NULL;
			char *bcnt = NULL;
			char *parsestart;

			/* the parser */
			char *curchar;
			int quote_open;
			int param_len;

			/* reset the newargv */
			newargc = 0;

			if (buffer[0] == '[') {
				/* we have counters in our input */
				ptr = strchr(buffer, ']');
				if (!ptr)
					exit_error(PARAMETER_PROBLEM,
						   "Bad line %u: need ]\n",
						   line);

				pcnt = strtok(buffer+1, ":");
				if (!pcnt)
					exit_error(PARAMETER_PROBLEM,
						   "Bad line %u: need :\n",
						   line);

				bcnt = strtok(NULL, "]");
				if (!bcnt)
					exit_error(PARAMETER_PROBLEM,
						   "Bad line %u: need ]\n",
						   line);

				/* start command parsing after counter */
				parsestart = ptr + 1;
			} else {
				/* start command parsing at start of line */
				parsestart = buffer;
			}

			add_argv(argv[0]);
			add_argv("-t");
			add_argv((char *) &curtable);
			
			if (counters && pcnt && bcnt) {
				add_argv("--set-counters");
				add_argv((char *) pcnt);
				add_argv((char *) bcnt);
			}

			/* After fighting with strtok enough, here's now
			 * a 'real' parser. According to Rusty I'm now no
			 * longer a real hacker, but I can live with that */

			quote_open = 0;
			param_len = 0;
			
			for (curchar = parsestart; *curchar; curchar++) {
				char param_buffer[1024];

				if (*curchar == '"') {
					/* quote_open cannot be true if there
					 * was no previous character.  Thus, 
					 * curchar-1 has to be within bounds */
					if (quote_open && 
					    *(curchar-1) != '\\') {
						quote_open = 0;
						*curchar = ' ';
					} else if (!quote_open) {
						quote_open = 1;
						continue;
					}
				} 
				if (*curchar == ' '
				    || *curchar == '\t'
				    || * curchar == '\n') {

					if (quote_open) {
						param_buffer[param_len++] = 
								*curchar;
						continue;
					}

					if (!param_len) {
						/* two spaces? */
						continue;
					}

					param_buffer[param_len] = '\0';

					/* check if table name specified */
					if (!strncmp(param_buffer, "-t", 3)
                                            || !strncmp(param_buffer, "--table", 8)) {
						exit_error(PARAMETER_PROBLEM, 
						   "Line %u seems to have a "
						   "-t table option.\n", line);
						exit(1);
					}

					add_argv(param_buffer);
					param_len = 0;
				} else {
					/* Skip backslash that escapes quote: 
					 * the standard input does not require
					 * escaping. However, the output
					 * generated by iptables-save
					 * introduces bashlash to keep
					 * consistent with iptables
					 */
					if (quote_open &&
					    *curchar == '\\' &&
					    *(curchar+1) == '"')
						continue;

					/* regular character, copy to buffer */
					param_buffer[param_len++] = *curchar;

					if (param_len >= sizeof(param_buffer))
						exit_error(PARAMETER_PROBLEM, 
						   "Parameter too long!");
				}
			}

			DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
				newargc, curtable);

			for (a = 0; a < newargc; a++)
				DEBUGP("argv[%u]: %s\n", a, newargv[a]);

			ret = do_command(newargc, newargv, 
					 &newargv[2], &handle);

			free_argv();
		}
		if (!ret) {
			fprintf(stderr, "%s: line %u failed\n",
					program_name, line);
			exit(1);
		}
	}
	if (in_table) {
		fprintf(stderr, "%s: COMMIT expected at line %u\n",
				program_name, line + 1);
		exit(1);
	}

	return 0;
}