Esempio n. 1
0
void *miniGgsnReadServiceLoop(void *arg)
{
	Ggsn *ggsn = (Ggsn*)arg;
	sethighpri();
	while (ggsn->active()) {
		struct pollfd fds[1];
		fds[0].fd = tun_fd;
		fds[0].events = POLLIN;
		fds[0].revents = 0;		// being cautious
		// We time out occassionally to check if the user wants to shut the sgsn down.
                MGINFO("ggsn: polling at %s",timestr().c_str());
		if (-1 == poll(fds,1,ggsn->mStopTimeout)) {
			SGSNERROR("ggsn: poll failure");
			return 0;
		}
                MGINFO("ggsn: polling %0x at %s",fds[0].revents,timestr().c_str());
		if (fds[0].revents & POLLIN) {
			miniggsn_handle_read();
		}
	}
	return 0;
}
Esempio n. 2
0
unsigned char *miniggsn_rcv_npdu(int *plen, uint32_t *dstaddr)
{
	static unsigned char *recvbuf = NULL;

	if (recvbuf == NULL) {
		recvbuf = (unsigned char*)malloc(ggConfig.mgMaxPduSize+2);
		if (!recvbuf) { /**error = -ENOMEM;*/ return NULL; }
	}

	// The O_NONBLOCK was set by default!  Is not happening any more.
	{
		int flags = fcntl(tun_fd,F_GETFL,0);
		if (flags & O_NONBLOCK) {
			//MGDEBUG(4,"O_NONBLOCK = %d",O_NONBLOCK & flags);
			flags &= ~O_NONBLOCK;	// Want Blocking!
			int fcntlstat = fcntl(tun_fd,F_SETFL,flags);
			MGWARN("ggsn: WARNING: Turning off tun_fd blocking flag, fcntl=%d",fcntlstat);
		}
	}

	// We can just read from the tunnel.
	int ret = read(tun_fd,recvbuf,ggConfig.mgMaxPduSize);
	if (ret < 0) {
		MGERROR("ggsn: error: reading from tunnel: %s", strerror(errno));
		//*error = ret;
		return NULL;
	} else if (ret == 0) {
		MGERROR("ggsn: error: zero bytes reading from tunnel: %s", strerror(errno));
		//*error = ret;	// huh?
		return NULL;
	} else {
		struct iphdr *iph = (struct iphdr*)recvbuf;
		{
			char infobuf[200];
			MGINFO("ggsn: received %s at %s",packettoa(infobuf,recvbuf,ret), timestr().c_str());
			//MGLOGF("ggsn: received proto=%s %d byte npdu from %s for %s at %s",
				//ip_proto_name(iph->protocol), ret,
				//ip_ntoa(iph->saddr,nbuf),
				//ip_ntoa(iph->daddr,NULL), timestr());
		}

		*dstaddr = iph->daddr;
		// TODO: Do we have to allocate a new buffer?
		*plen = ret;
		// Zero terminate for the convenience of the pinger.
		recvbuf[ret] = 0;
		return recvbuf;
	}
}
Esempio n. 3
0
// If this is a duplicate TCP packet, throw it away.
// The MS is so slow to respond that the servers often send dups
// which are unnecessary because we have reliable communication between here
// and the MS, so just toss them.
// Update 3-2012: Always do the check to print messages for dup packets even if not discarded.
static int mg_toss_dup_packet(mg_con_t*mgp,unsigned char *packet, int packetlen)
{
	struct iphdr *iph = (struct iphdr*)packet;
	if (iph->protocol != IPPROTO_TCP) { return 0; }
	struct tcphdr *tcph = (struct tcphdr*) (packet + 4 * iph->ihl);
	if (tcph->rst | tcph->urg) { return 0; }
	int i;
	for (i = 0; i < MG_PACKET_HISTORY; i++) {
		// 3-2012: Jpegs are not going through the system properly.
		// I am adding some more checks here to see if we are tossing packets inappropriately.
		// The tot_len includes headers, but if they are not the same in the duplicate packet, oh well.
		// TODO: If the connection is reset we should zero out our history.
		if (mgp->mg_packets[i].saddr == iph->saddr &&
		    mgp->mg_packets[i].daddr == iph->daddr &&
		    mgp->mg_packets[i].totlen == iph->tot_len &&
		    //mgp->mg_packets[i].ipfragoff == iph->frag_off &&
		    //mgp->mg_packets[i].ipid == iph->id &&
		    mgp->mg_packets[i].seq == tcph->seq &&
		    mgp->mg_packets[i].source == tcph->source &&
		    mgp->mg_packets[i].dest == tcph->dest
			) {
				const char *what = ggConfig.mgIpTossDup ? "discarding " : "";
				char buf1[40],buf2[40];
				MGINFO("ggsn: %sduplicate %d byte packet seq=%d frag=%d id=%d src=%s:%d dst=%s:%d",what,
					packetlen,tcph->seq,iph->frag_off,iph->id,
					ip_ntoa(iph->saddr,buf1),tcph->source,
					ip_ntoa(iph->daddr,buf2),tcph->dest);
				return ggConfig.mgIpTossDup;	// Toss duplicate tcp packet if option set.
			}
	}
	i = mgp->mg_oldest_packet;
	if (++mgp->mg_oldest_packet >= MG_PACKET_HISTORY) { mgp->mg_oldest_packet = 0; }
	mgp->mg_packets[i].saddr = iph->saddr;
	mgp->mg_packets[i].daddr = iph->daddr;
	mgp->mg_packets[i].totlen = iph->tot_len;
	//mgp->mg_packets[i].ipfragoff = iph->frag_off;
	//mgp->mg_packets[i].ipid = iph->id;
	mgp->mg_packets[i].seq = tcph->seq;
	mgp->mg_packets[i].source = tcph->source;
	mgp->mg_packets[i].dest = tcph->dest;
	return 0;	// Do not toss.
}
Esempio n. 4
0
DNSResolver::DNSResolver() : m_data(new DNSResolverData())
{
  int use_dns_public = 0;
  std::vector<std::string> dns_public_addr;
  if (auto res = getenv("DNS_PUBLIC"))
  {
    dns_public_addr = tools::dns_utils::parse_dns_public(res);
    if (!dns_public_addr.empty())
    {
      MGINFO("Using public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)");
      use_dns_public = 1;
    }
    else
    {
      MERROR("Failed to parse DNS_PUBLIC");
    }
  }

  // init libunbound context
  m_data->m_ub_context = ub_ctx_create();

  if (use_dns_public)
  {
    for (const auto &ip: dns_public_addr)
      ub_ctx_set_fwd(m_data->m_ub_context, string_copy(ip.c_str()));
    ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no"));
    ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes"));
  }
  else {
    // look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent
    ub_ctx_resolvconf(m_data->m_ub_context, NULL);
    ub_ctx_hosts(m_data->m_ub_context, NULL);
  }

  const char * const *ds = ::get_builtin_ds();
  while (*ds)
  {
    MINFO("adding trust anchor: " << *ds);
    ub_ctx_add_ta(m_data->m_ub_context, string_copy(*ds++));
  }
}
Esempio n. 5
0
std::tuple<bool, std::string, std::string, std::string, std::string> WalletManager::checkUpdates(const std::string &software, std::string subdir)
{
#ifdef BUILD_TAG
    static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
#else
    static const char buildtag[] = "source";
    // Override the subdir string when built from source
    subdir = "source";
#endif

    std::string version, hash;
    MDEBUG("Checking for a new " << software << " version for " << buildtag);
    if (!tools::check_updates(software, buildtag, version, hash))
      return std::make_tuple(false, "", "", "", "");

    if (tools::vercmp(version.c_str(), MONERO_VERSION) > 0)
    {
      std::string user_url = tools::get_update_url(software, subdir, buildtag, version, true);
      std::string auto_url = tools::get_update_url(software, subdir, buildtag, version, false);
      MGINFO("Version " << version << " of " << software << " for " << buildtag << " is available: " << user_url << ", SHA256 hash " << hash);
      return std::make_tuple(true, version, hash, user_url, auto_url);
    }
    return std::make_tuple(false, "", "", "", "");
}
Esempio n. 6
0
bool miniggsn_init()
{
	static int initstatus = -1;		// -1: uninited; 0:init failed; 1: init succeeded.
	if (initstatus >= 0) {return initstatus;}
	initstatus = 0;	// assume failure.


	// We init config options at GGSN startup.
	// They cannot be changed while running.
	// To change an option, you would have to stop and restart the GGSN.
	ggConfig.mgIpTimeout = gConfig.getNum(SQL_IP_TIMEOUT);
	ggConfig.mgMaxPduSize = gConfig.getNum(SQL_PDU_MAX_SIZE);
	ggConfig.mgMaxConnections = gConfig.getNum(SQL_PDP_MAX_COUNT);
	ggConfig.mgIpTossDup = gConfig.getNum(SQL_IP_TOSS_DUP);


	string logfile = gConfig.getStr(SQL_LOG_FILE);
	if (logfile.length()) {
		mg_log_fp = fopen(logfile.c_str(),"w");
		if (mg_log_fp == 0) {
			MGERROR("could not open %s log file:%s",SQL_LOG_FILE,logfile.c_str());
			// (pat) Add an alert to the console so people will notice this problem.
			LOG(ALERT) << "Cound not open tun device, GPRS non-functional:";
		}
	}

	// This is the first message in the newly opened file.
	time(&gGgsnInitTime);
	MGINFO("Initializing Mini GGSN %s",ctime(&gGgsnInitTime));	// ctime includes a newline.

	if (mg_log_fp) {
		mg_debug_level = 1;
		MGINFO("GGSN logging to file %s",logfile.c_str());
	}

	if (ggConfig.mgMaxConnections > 254) {
		MGERROR("%s specifies too many connections (%d) specifed, using 254",
			SQL_PDP_MAX_COUNT,ggConfig.mgMaxConnections);
		ggConfig.mgMaxConnections = 254;
	}

	// We need three IP things:
	// 1. the route expressed using "/maskbits" notation,
	// 2. the base ip address,
	// 3. the mask for the MS (which has very little to do with the netmask of the host we are running on.)
	// All three can be derived from the ipRoute, if specfied.
	// But conceivably the user might want to start their base ip address elsewhere.

	const char *ip_base_str = gConfig.getStr(SQL_IP_BASE).c_str();
	uint32_t mgIpBasenl = inet_addr(ip_base_str);
	if (mgIpBasenl == INADDR_NONE) {
		MGERROR("miniggsn: %s address invalid:%s",SQL_IP_BASE,ip_base_str);
		return false;
	}

	if ((ntohl(mgIpBasenl) & 0xff) == 0) {
		MGERROR("miniggsn: %s address should not end in .0 but proceeding anyway: %s",SQL_IP_BASE,ip_base_str);
	}

	//const char *route_str = DEFAULT_IP_ROUTE;
	const char *route_str = 0;
	char route_buf[40];
	string route_save;
	if (gConfig.defines(SQL_IP_ROUTE)) {
		route_save = gConfig.getStr(SQL_IP_ROUTE);
		route_str = route_save.c_str();
	}

	uint32_t route_basenl, route_masknl;
	if (route_str && *route_str && *route_str != ' ') {
		if (strlen(route_str) > strlen("aaa.bbb.ccc.ddd/yy") + 2) {	// add some slop.
			MGWARN("miniggsn: %s address is too long:%s",SQL_IP_ROUTE,route_str);
			// but use it anyway.
		}

		if (! ip_addr_crack(route_str,&route_basenl,&route_masknl) || route_basenl == INADDR_NONE) {
			MGWARN("miniggsn: %s is not a valid ip address: %s",SQL_IP_ROUTE,route_str);
			// but use it anyway.
		}
		if (route_masknl == 0) {
			MGWARN("miniggsn: %s is not a valid route, /mask part missing or invalid: %sn",
				SQL_IP_ROUTE,route_str);
			// but use it anyway.
		}

		// We would like to check that the base ip is within the ip route range,
		// which is tricky, but check the most common case:
		if ((route_basenl&route_masknl) != (mgIpBasenl&route_masknl)) {
			MGWARN("miniggsn: %s = %s ip address does not appear to be in range of %s = %s",
				SQL_IP_BASE, ip_base_str, SQL_IP_ROUTE,route_str);
			// but use it anyway.
		}
	} else {
		// Manufacture a route string.  Assume route is 24 bits.
		route_masknl = inet_addr("255.255.255.0");
		route_basenl = mgIpBasenl & route_masknl;	// Set low byte to 0.
		ip_ntoa(route_basenl,route_buf);
		strcat(route_buf,"/24");
		route_str = route_buf;
	}

	// Firewall rules:
	bool firewall_enable;
	if ((firewall_enable = gConfig.getNum(SQL_FIREWALL_ENABLE))) {
		// Block anything in the routed range:
		addFirewallRule(route_basenl,route_masknl);
		// Block local loopback:
		uint32_t tmp_basenl,tmp_masknl;
		if (ip_addr_crack("127.0.0.1/24",&tmp_basenl,&tmp_masknl)) {
			addFirewallRule(tmp_basenl,tmp_masknl);
		}
		// Block the OpenBTS station itself:
		uint32_t *myaddrs = ip_findmyaddr();
		for ( ; *myaddrs != (unsigned)-1; myaddrs++) {
			addFirewallRule(*myaddrs,0xffffffff);
		}
		if (firewall_enable >= 2) {
			// Block all private addresses:
			// 16-bit block (/16 prefix, 256 × C) 	192.168.0.0 	192.168.255.255 	65536
			uint32_t private_addrnl = inet_addr("192.168.0.0");
			uint32_t private_masknl = inet_addr("255.255.0.0");
			addFirewallRule(private_addrnl,private_masknl);
			// 20-bit block (/12 prefix, 16 × B) 	172.16.0.0 	172.31.255.255 	1048576
			private_addrnl = inet_addr("172.16.0.0");
			private_masknl = inet_addr("255.240.0.0");
			addFirewallRule(private_addrnl,private_masknl);
			// 24-bit block (/8 prefix, 1 × A) 	10.0.0.0 	10.255.255.255 	16777216
			private_addrnl = inet_addr("10.0.0.0");
			private_masknl = inet_addr("255.0.0.0");
			addFirewallRule(private_addrnl,private_masknl);
		}
	}

	MGINFO("GGSN Configuration:");
		MGINFO("  %s=%s", SQL_IP_BASE, ip_ntoa(mgIpBasenl,NULL));
		MGINFO("  %s=%d", SQL_PDP_MAX_COUNT, ggConfig.mgMaxConnections);
		MGINFO("  %s=%s", SQL_IP_ROUTE, route_str);
		MGINFO("  %s=%d", SQL_PDU_MAX_SIZE, ggConfig.mgMaxPduSize);
		MGINFO("  %s=%d", SQL_IP_TIMEOUT, ggConfig.mgIpTimeout);
		MGINFO("  %s=%d", SQL_FIREWALL_ENABLE, firewall_enable);
		MGINFO("  %s=%d", SQL_IP_TOSS_DUP, ggConfig.mgIpTossDup);
	if (firewall_enable) {
		MGINFO("GGSN Firewall Rules:");
		for (GgsnFirewallRule *rp = gFirewallRules; rp; rp = rp->next) {
			char buf1[40], buf2[40];
			MGINFO("  block ip=%s mask=%s",ip_ntoa(rp->ipBasenl,buf1),ip_ntoa(rp->ipMasknl,buf2));
		}
	}
	uint32_t dns[2];	// We dont use the result, we just want to print out the DNS servers now.
	ip_finddns(dns);	// The dns servers are polled again later.

	const char *tun_if_name = gConfig.getStr(SQL_TUN_IF_NAME).c_str();

	if (tun_fd == -1) {
		ip_init();
		tun_fd = ip_tun_open(tun_if_name,route_str);
		if (tun_fd < 0) {
			MGERROR("ggsn: ERROR: Could not open tun device %s",tun_if_name);
			return false;
		}
	}

	// DEBUG: Try it again.
	//printf("DEBUG: Opening tunnel again: %d\n",ip_tun_open(tun_if_name,route_str));

	if (mg_cons) free(mg_cons);
	mg_cons = (mg_con_t*)calloc(ggConfig.mgMaxConnections,sizeof(mg_con_t));
	if (mg_cons == 0) {
		MGERROR("ggsn: ERROR: out of memory");
		return false;
	}
	//memset(mg_cons,0,sizeof(mg_cons));

	uint32_t base_iphl = ntohl(mgIpBasenl);
	// 8-15:  no dont do this.  It subverts the purpose of the BASE ip address.
	//base_iphl &= ~255;			// In case they specify 192.168.2.1, make it 192.168.2.0
	int i;
	// If the last digit is 0 (192.168.99.0), change it to 1 for the first IP addr served.
	if ((base_iphl & 255) == 0) { base_iphl++; }
	for (i=0; i < ggConfig.mgMaxConnections; i++) {
		mg_cons[i].mg_ip = htonl(base_iphl + i);
		//mg_cons[i].mg_ip = htonl(base_iphl + 1 + i);
		// DEBUG!!!!!  Use my own ip address.
		//mg_cons[i].mg_ip = inet_addr("192.168.1.99");
		//printf("adding IP=%s\n",ip_ntoa(mg_cons[i].mg_ip,NULL));
	}
	initstatus = 1;
	return initstatus;
}
Esempio n. 7
0
// The npdu is a raw packet including the ip header.
int miniggsn_snd_npdu_by_mgc(mg_con_t *mgp,unsigned char *npdu, unsigned len)
{
    // Verify the IP header.
    struct iphdr *ipheader = (struct iphdr*)npdu;
    // The return address must be the MS itself.
    uint32_t ms_ip_address = mgp->mg_ip;
    uint32_t packet_source_ip_addr = ipheader->saddr;
    uint32_t packet_dest_ip_addr = ipheader->daddr;

	char infobuf[200];
	MGINFO("ggsn: writing %s at %s",packettoa(infobuf,npdu,len),timestr().c_str());
	//MGLOGF("ggsn: writing proto=%s %d byte npdu to %s from %s at %s",
		//ip_proto_name(ipheader->protocol),
		//len,ip_ntoa(packet_dest_ip_addr,NULL),
		//ip_ntoa(packet_source_ip_addr,nbuf), timestr().c_str());

#define MUST_HAVE(assertion) \
    if (! (assertion)) { MGERROR("ggsn: Packet failed test, discarded: %s",#assertion); return -1; }

    if (mg_debug_level > 2) ip_hdr_dump(npdu,"npdu");
    MUST_HAVE(ipheader->version == 4);	// 4 as in IPv4
    MUST_HAVE(ipheader->ihl >= 5);		// Minimum header length is 5 words.

    int checksum = ip_checksum(ipheader,sizeof(*ipheader),NULL);
    MUST_HAVE(checksum == 0);				// If fails, packet is bad.

    MUST_HAVE(ipheader->ttl > 0);		// Time to live - how many hops allowed.


	// The blackberry sends ICMP packets, so we better support.
	// I'm just going to allow any protocol through.
    //MUST_HAVE(ipheader->protocol == IPPROTO_TCP || 
	//	ipheader->protocol == IPPROTO_UDP ||
	//	ipheader->protocol == IPPROTO_ICMP);

    MUST_HAVE(packet_source_ip_addr == ms_ip_address);

#if OLD_FIREWALL
    // The destination address may not be a local address on this machine
	// as configured by the operator.
	// Note these are all in network order, so be careful.
    //uint32_t local_ip_addr = inet_addr(mg_base_ip_str); // probably "192.168.99.1"
	uint32_t net_mask = inet_addr(mg_net_mask);			// probably "255.255.255.0"
    MUST_HAVE((packet_dest_ip_addr & net_mask) != (local_ip_addr & net_mask));
#endif

	for (GgsnFirewallRule *rp = gFirewallRules; rp; rp = rp->next) {
		MUST_HAVE((packet_dest_ip_addr & rp->ipMasknl) != (rp->ipBasenl & rp->ipMasknl));
	}

    // Decrement ttl and recompute checksum.  We are doing this in place.
    ipheader->ttl--;
    ipheader->check = 0;
    //ipheader->check = htons(ip_checksum(ipheader,sizeof(*ipheader),NULL));
    ipheader->check = ip_checksum(ipheader,sizeof(*ipheader),NULL);

	// Just write to the MS-side tunnel device.

	int result = write(tun_fd,npdu,len);
	if (result != (int) len) {
		MGERROR("ggsn: error: write(tun_fd,%d) result=%d %s",len,result,strerror(errno));
	}
    return 0;
}