Example #1
0
void CHTTPSock::ReadLine(const CString& sData) {
	if (m_bGotHeader) {
		return;
	}

	CString sLine = sData;
	sLine.TrimRight("\r\n");

	CString sName = sLine.Token(0);

	if (sName.Equals("GET")) {
		m_bPost = false;
		m_sURI = sLine.Token(1);
		m_bHTTP10Client = sLine.Token(2).Equals("HTTP/1.0");
		ParseURI();
	} else if (sName.Equals("POST")) {
		m_bPost = true;
		m_sURI = sLine.Token(1);
		ParseURI();
	} else if (sName.Equals("Cookie:")) {
		VCString vsNV;

		sLine.Token(1, true).Split(";", vsNV, false, "", "", true, true);

		for (const CString& s : vsNV) {
			m_msRequestCookies[s.Token(0, false, "=").Escape_n(CString::EURL, CString::EASCII)] =
				s.Token(1, true, "=").Escape_n(CString::EURL, CString::EASCII);
		}
	} else if (sName.Equals("Authorization:")) {
		CString sUnhashed;
		sLine.Token(2).Base64Decode(sUnhashed);
		m_sUser = sUnhashed.Token(0, false, ":");
		m_sPass = sUnhashed.Token(1, true, ":");
		m_bBasicAuth = true;
		// Postpone authorization attempt until end of headers, because cookies should be read before that, otherwise session id will be overwritten in GetSession()
	} else if (sName.Equals("Content-Length:")) {
		m_uPostLen = sLine.Token(1).ToULong();
		if (m_uPostLen > MAX_POST_SIZE)
			PrintErrorPage(413, "Request Entity Too Large", "The request you sent was too large.");
	} else if (sName.Equals("X-Forwarded-For:")) {
		// X-Forwarded-For: client, proxy1, proxy2
		if (m_sForwardedIP.empty()) {
			const VCString& vsTrustedProxies = CZNC::Get().GetTrustedProxies();
			CString sIP = GetRemoteIP();

			VCString vsIPs;
			sLine.Token(1, true).Split(",", vsIPs, false, "", "", false, true);

			while (!vsIPs.empty()) {
				// sIP told us that it got connection from vsIPs.back()
				// check if sIP is trusted proxy
				bool bTrusted = false;
				for (const CString& sTrustedProxy : vsTrustedProxies) {
					if (sIP.WildCmp(sTrustedProxy)) {
						bTrusted = true;
						break;
					}
				}
				if (bTrusted) {
					// sIP is trusted proxy, so use vsIPs.back() as new sIP
					sIP = vsIPs.back();
					vsIPs.pop_back();
				} else {
					break;
				}
			}

			// either sIP is not trusted proxy, or it's in the beginning of the X-Forwarded-For list
			// in both cases use it as the endpoind
			m_sForwardedIP = sIP;
		}
	} else if (sName.Equals("If-None-Match:")) {
		// this is for proper client cache support (HTTP 304) on static files:
		m_sIfNoneMatch = sLine.Token(1, true);
	} else if (sName.Equals("Accept-Encoding:") && !m_bHTTP10Client) {
		SCString ssEncodings;
		// trimming whitespace from the tokens is important:
		sLine.Token(1, true).Split(",", ssEncodings, false, "", "", false, true);
		m_bAcceptGzip = (ssEncodings.find("gzip") != ssEncodings.end());
	} else if (sLine.empty()) {
		if (m_bBasicAuth && !m_bLoggedIn) {
			m_bLoggedIn = OnLogin(m_sUser, m_sPass, true);
			// After successful login ReadLine("") will be called again to trigger "else" block
			// Failed login sends error and closes socket, so no infinite loop here
		} else {
			m_bGotHeader = true;

			if (m_bPost) {
				m_sPostData = GetInternalReadBuffer();
				CheckPost();
			} else {
				GetPage();
			}

			DisableReadLine();
		}
	}
}
Example #2
0
bool CUser::IsHostAllowed(const CString& sHostMask) const {
    if (m_ssAllowedHosts.empty()) {
        return true;
    }

    for (const CString& sHost : m_ssAllowedHosts) {
        if (sHostMask.WildCmp(sHost)) {
            return true;
        } else {
            // CIDR notation checker, e.g. "192.0.2.0/24" or "2001:db8::/32"

            // Try to split the string into an IP and routing prefix
            VCString vsSplitCIDR;
            if (sHost.Split("/", vsSplitCIDR, false) != 2) continue;
            const CString sRoutingPrefix = vsSplitCIDR.back();
            const int iRoutingPrefix = sRoutingPrefix.ToInt();
            if (iRoutingPrefix < 0 || iRoutingPrefix > 128) continue;

            // If iRoutingPrefix is 0, it could be due to ToInt() failing, so
            // sRoutingPrefix needs to be all zeroes
            if (iRoutingPrefix == 0 && sRoutingPrefix != "0") continue;

            // Convert each IP from a numeric string to an addrinfo
            addrinfo aiHints;
            memset(&aiHints, 0, sizeof(addrinfo));
            aiHints.ai_flags = AI_NUMERICHOST;

            addrinfo* aiHost;
            int iIsHostValid =
                getaddrinfo(sHostMask.c_str(), nullptr, &aiHints, &aiHost);
            if (iIsHostValid != 0) continue;

            aiHints.ai_family = aiHost->ai_family;  // Host and range must be in
                                                    // the same address family

            addrinfo* aiRange;
            int iIsRangeValid = getaddrinfo(vsSplitCIDR.front().c_str(),
                                            nullptr, &aiHints, &aiRange);
            if (iIsRangeValid != 0) {
                freeaddrinfo(aiHost);
                continue;
            }

            // "/0" allows all IPv[4|6] addresses
            if (iRoutingPrefix == 0) {
                freeaddrinfo(aiHost);
                freeaddrinfo(aiRange);
                return true;
            }

            // If both IPs are valid and of the same type, make a bit field mask
            // from the routing prefix, AND it to the host and range, and see if
            // they match
            bool bIsHostInRange = false;
            if (aiHost->ai_family == AF_INET) {
                if (iRoutingPrefix > 32) {
                    freeaddrinfo(aiHost);
                    freeaddrinfo(aiRange);
                    continue;
                }

                const sockaddr_in* saHost = (sockaddr_in*)(aiHost->ai_addr);
                const sockaddr_in* saRange = (sockaddr_in*)(aiRange->ai_addr);

                // Make IPv4 bitmask
                const in_addr_t inBitmask =
                    htonl((~0u) << (32 - iRoutingPrefix));

                // Compare masked IPv4s
                bIsHostInRange = ((inBitmask & saHost->sin_addr.s_addr) ==
                                  (inBitmask & saRange->sin_addr.s_addr));
            } else if (aiHost->ai_family == AF_INET6) {
                // Make IPv6 bitmask
                in6_addr in6aBitmask;
                memset(&in6aBitmask, 0, sizeof(in6aBitmask));

                for (int i = 0, iBitsLeft = iRoutingPrefix; iBitsLeft > 0;
                     ++i, iBitsLeft -= 8) {
                    if (iBitsLeft >= 8) {
                        in6aBitmask.s6_addr[i] = (uint8_t)(~0u);
                    } else {
                        in6aBitmask.s6_addr[i] = (uint8_t)(~0u)
                                                 << (8 - iBitsLeft);
                    }
                }

                // Compare masked IPv6s
                bIsHostInRange = true;
                const sockaddr_in6* sa6Host = (sockaddr_in6*)(aiHost->ai_addr);
                const sockaddr_in6* sa6Range =
                    (sockaddr_in6*)(aiRange->ai_addr);

                for (int i = 0; i < 16; ++i) {
                    if ((in6aBitmask.s6_addr[i] &
                         sa6Host->sin6_addr.s6_addr[i]) !=
                        (in6aBitmask.s6_addr[i] &
                         sa6Range->sin6_addr.s6_addr[i])) {
                        bIsHostInRange = false;
                    }
                }
            }

            freeaddrinfo(aiHost);
            freeaddrinfo(aiRange);

            if (bIsHostInRange) return true;
        }
    }

    return false;
}