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; }
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; } }
// 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. }
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++)); } }
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, "", "", "", ""); }
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; }
// 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; }