Beispiel #1
0
// Returns the IP address (IPv4 if possible) for the machine with the given name.
// The name may or may not include a domain.
// Returns "none" if the IP address could not be determined.
//
// ATTENTION! This function accesses a variety of external sources
// and may therefore take a while. If possible you should use it asynchronously.
func SystemIPAddressForName(host string) string {
	ip, err := util.Resolve(host, config.IP)
	if err != nil {
		// if host already contains a domain, give up
		if strings.Index(host, ".") >= 0 {
			util.Log(0, "ERROR! Resolve(\"%v\"): %v", host, err)
			return "none"
		}

		// if host does not contain a domain the DNS failure may simple be
		// caused by the machine being in a different subdomain. Try to
		// work around this by searching LDAP for the machine and use its
		// ipHostNumber if it is accurate.
		util.Log(1, "INFO! Could not resolve short name %v (error: %v). Trying LDAP.", host, err)
		var system *xml.Hash
		system, err = xml.LdifToHash("", true, ldapSearch(fmt.Sprintf("(&(objectClass=GOhard)(|(cn=%v)(cn=%v.*))%v)", LDAPFilterEscape(host), LDAPFilterEscape(host), config.UnitTagFilter), "ipHostNumber"))
		// the search may give multiple results. Use reverse lookup of ipHostNumber to
		// find the correct one (if there is one)
		for ihn := system.First("iphostnumber"); ihn != nil; ihn = ihn.Next() {
			ip := ihn.Text()
			fullname := SystemNameForIPAddress(ip)
			if strings.HasPrefix(fullname, host+".") {
				util.Log(1, "INFO! Found \"%v\" with IP %v in LDAP", fullname, ip)
				// use forward lookup for the full name to be sure we get the proper address
				return SystemIPAddressForName(fullname)
			}
		}
		util.Log(0, "ERROR! Could not get reliable IP address for %v from LDAP", host)
		return "none"
	}

	return ip
}
Beispiel #2
0
// Returns a PeerConnection for talking to addr, which can be either
// IP:ADDR or HOST:ADDR (where HOST is something that DNS can resolve).
func Peer(addr string) *PeerConnection {
	addr, err := util.Resolve(addr, config.IP)
	if err != nil {
		return &PeerConnection{err: err}
	}

	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		return &PeerConnection{err: err}
	}

	addr = host + ":" + port

	if addr == config.ServerSourceAddress {
		panic("Peer() called with my own address. This is a bug!")
	}

	connections_mutex.Lock()
	defer connections_mutex.Unlock()

	conn, have_already := connections[addr]
	if !have_already {
		conn = &PeerConnection{is_gosusi: false, addr: addr}
		connections[addr] = conn
		go util.WithPanicHandler(func() { conn.handleConnection() })
	}
	return conn
}
Beispiel #3
0
// Tries to re-establish communication with a client/server at the given IP,
// by
//   1) sending here_i_am to the server where we are registered. We do this
//      even if config.RunServer (i.e. we are registered at ourselves) because
//      this will trigger new_foreign_client messages sent to peers so that other
//      servers that may believe they own us correct their data.
//   2) sending (if config.RunServer) new_server messages to all known servers
//      we find for the IP in our servers database.
//   3) if config.RunServer and in 2) we did not find a server at that IP,
//      maybe it's a client that thinks we are its server. Send "deregistered" to
//      all ClientPorts in that case to cause re-registration.
func tryToReestablishCommunicationWith(ip string) {
	// Wait a little to limit the rate of spam wars between
	// 2 machines that can't re-establish communication (e.g. because of changed
	// keys in server.conf).
	mapIP2ReestablishDelay_mutex.Lock()
	var delay time.Duration
	var ok bool
	if delay, ok = mapIP2ReestablishDelay[ip]; !ok {
		delay = 1 * time.Minute
	}
	mapIP2ReestablishDelay[ip] = 2 * delay
	mapIP2ReestablishDelay_mutex.Unlock()

	// if the delay exceeds 24h this means that we got multiple
	// reestablish requests while we're still waiting to begin one
	// in that case, bail out.
	if delay > 24*time.Hour {
		return
	}

	util.Log(0, "WARNING! Will try to re-establish communication with %v after waiting %v", ip, delay)
	time.Sleep(delay)

	// if we actually completed a 10h wait, reset the timer to 1 minute
	if delay >= 10*time.Hour {
		mapIP2ReestablishDelay_mutex.Lock()
		mapIP2ReestablishDelay[ip] = 1 * time.Minute
		mapIP2ReestablishDelay_mutex.Unlock()
	}

	util.Log(0, "WARNING! Will try to re-establish communication with %v", ip)
	ConfirmRegistration() // 1)

	ip, err := util.Resolve(ip, config.IP)
	if err != nil {
		util.Log(0, "ERROR! Resolve(): %v", err)
	}

	if config.RunServer { // 2)
		sendmuell := true
		for _, server := range db.ServerAddresses() {
			if strings.HasPrefix(server, ip) {
				sendmuell = false
				srv := server
				go util.WithPanicHandler(func() { Send_new_server("new_server", srv) })
			}
		}

		if sendmuell {
			for _, port := range config.ClientPorts {
				addr := ip + ":" + port
				if addr != config.ServerSourceAddress { // never send "deregistered" to our own server
					dereg := "<xml><header>deregistered</header><source>" + config.ServerSourceAddress + "</source><target>" + addr + "</target></xml>"
					go security.SendLnTo(addr, dereg, "", false)
				}
			}
		}
	}
}
Beispiel #4
0
// Handles the message "confirm_new_server".
//  xmlmsg: the decrypted and parsed message
func confirm_new_server(xmlmsg *xml.Hash) {
	server, _ := util.Resolve(xmlmsg.Text("source"), config.IP)
	if server == config.ServerSourceAddress {
		return
	} // never accept our own address as peer
	setGoSusi(xmlmsg)
	handleClients(xmlmsg)
	Peer(xmlmsg.Text("source")).SyncAll()
	db.ServerUpdate(xmlmsg)
}
Beispiel #5
0
// Handles the message "new_server".
//  xmlmsg: the decrypted and parsed message
func new_server(xmlmsg *xml.Hash) {
	server, _ := util.Resolve(xmlmsg.Text("source"), config.IP)
	if server == config.ServerSourceAddress {
		return
	} // never accept our own address as peer
	setGoSusi(xmlmsg)
	db.ServerUpdate(xmlmsg)
	handleClients(xmlmsg)
	go util.WithPanicHandler(func() {
		Send_new_server("confirm_new_server", server)
		Peer(server).SyncAll()
	})
	return
}
Beispiel #6
0
// Adds server (host:port) to the database if it does not exist yet (and if it
// is not identical to this go-susi).
func addServer(server string) {
	server, err := util.Resolve(server, config.IP)
	if err != nil {
		util.Log(0, "ERROR! util.Resolve(\"%v\"): %v", server, err)
		return
	}
	ip, port, err := net.SplitHostPort(server)
	if err != nil {
		util.Log(0, "ERROR! net.SplitHostPort(\"%v\"): %v", server, err)
		return
	}

	source := ip + ":" + port

	// do not add our own address
	if source == config.ServerSourceAddress {
		return
	}

	// if we don't have an entry for the server, generate a dummy entry.
	if len(ServerKeys(source)) == 0 {
		// There's no point in generating a random server key.
		// First of all, the server key is only as secure as the ServerPackages
		// module key (because whoever has that can decrypt the message that
		// contains the server key).
		// Secondly the whole gosa-si protocol is not really secure. For instance
		// there is lots of known plaintext and no salting of messages. And the
		// really important messages are all encrypted with fixed keys anyway.
		// So instead of pretending more security by generating a random key,
		// we make debugging a little easier by generating a unique key derived
		// from the ServerPackages module key.
		var key string
		if ip < config.IP {
			key = ip + config.IP
		} else {
			key = config.IP + ip
		}
		key = config.ModuleKey["[ServerPackages]"] + strings.Replace(key, ".", "", -1)
		server_xml := xml.NewHash("xml", "source", source)
		// If we have a TLS config, assume the peer does, too, and mark it as
		// such by storing an empty string as key.
		if config.TLSClientConfig != nil {
			key = ""
		}
		server_xml.Add("key", key)
		ServerUpdate(server_xml)
	}
}
// Returns a ClientConnection for talking to addr, which can be either
// IP:PORT or HOST:PORT (where HOST is something that DNS can resolve).
func Client(addr string) *ClientConnection {
	addr, err := util.Resolve(addr, config.IP)
	if err != nil {
		util.Log(0, "ERROR! Client(%v): %v", addr, err)
		return &ClientConnection{addr: "127.0.0.1:0"}
	}

	_, _, err = net.SplitHostPort(addr)
	if err != nil {
		util.Log(0, "ERROR! Client(%v): %v", addr, err)
		return &ClientConnection{addr: "127.0.0.1:0"}
	}

	client_connections_mutex.Lock()
	defer client_connections_mutex.Unlock()

	conn, have_already := client_connections[addr]
	if !have_already {
		conn = &ClientConnection{addr: addr}
		client_connections[addr] = conn
	}
	return conn
}
Beispiel #8
0
// Reads network parameters.
func ReadNetwork() {
	var err error

	var ifaces []net.Interface
	ifaces, err = net.Interfaces()
	if err != nil {
		util.Log(0, "ERROR! ReadNetwork: %v", err)
	} else {
		best_interface_weight := -1

		// find non-loopback interfaces that are up
		for _, iface := range ifaces {
			if iface.Flags&net.FlagLoopback != 0 {
				continue
			}
			if iface.Flags&net.FlagUp == 0 {
				continue
			}

			ifaceInfo := InterfaceInfo{}
			ifaceInfo.Interface = iface

			var addrs []net.Addr
			addrs, err = iface.Addrs()
			if err == nil {

				// find the first IP address for that interface
				for _, addr := range addrs {
					ip, _, err2 := net.ParseCIDR(addr.String())
					if err2 == nil && !ip.IsLoopback() {
						ifaceInfo.IP = ip.String()
						goto FoundIP
					}
				}
				err = fmt.Errorf("Could not determine IP for interface %v", iface.HardwareAddr.String())
			FoundIP:
			}

			if err != nil {
				ifaceInfo.IP = fmt.Sprintf("ERROR! %v", err)
				ifaceInfo.Hostname = ifaceInfo.IP
				ifaceInfo.Domain = ifaceInfo.IP
			} else {
				var names []string
				names, err = net.LookupAddr(ifaceInfo.IP)
				//util.Log(2, "DEBUG! Names for %v: %v", ifaceInfo.IP, names)
				if err == nil {
					for _, name := range names {
						name = strings.Trim(name, ".")
						if name == "" {
							continue
						}

						// if we have no hostname yet, use the name from the address
						// if this includes a "." we'll chop off the domain in the if below
						if ifaceInfo.Hostname == "" {
							ifaceInfo.Hostname = name
						}

						i := strings.Index(name, ".")
						if i > 0 {
							ifaceInfo.Hostname = name[0:i]
							ifaceInfo.Domain = name[i+1:]
							goto DomainFound
						}
					}
					err = fmt.Errorf("Could not determine domain. Lookup of IP %v returned %v", ifaceInfo.IP, names)
				DomainFound:
				}

				if err != nil {
					if ifaceInfo.Hostname == "" {
						ifaceInfo.Hostname = fmt.Sprintf("ERROR! %v", err)
					}
					ifaceInfo.Domain = fmt.Sprintf("ERROR! %v", err)
				}
			}

			if !strings.HasPrefix(ifaceInfo.Domain, "ERROR!") {
				var addrs []*net.SRV
				_, addrs, err := net.LookupSRV("gosa-si", "tcp", ifaceInfo.Domain)
				if err != nil {
					util.Log(1, "INFO! LookupSRV(\"gosa-si\",\"tcp\",\"%v\"): %v", ifaceInfo.Domain, err)
				} else {
					ifaceInfo.Peers = addrs
				}
			}

			Interfaces = append(Interfaces, ifaceInfo)

			weight := 0
			if !strings.HasPrefix(ifaceInfo.IP, "ERROR!") {
				weight += 1
			}
			if !strings.HasPrefix(ifaceInfo.Hostname, "ERROR!") {
				weight += 2
			}
			if !strings.HasPrefix(ifaceInfo.Domain, "ERROR!") {
				weight += 4
			}
			if len(ifaceInfo.Peers) > 0 {
				weight += 8
			}

			if BestInterface < 0 || weight > best_interface_weight {
				BestInterface = len(Interfaces) - 1
				best_interface_weight = weight
			}
		}
	}

	// use os.Hostname as default in case we can't get a host name from an interface
	var hostname string
	hostname, err = os.Hostname()
	if err == nil {
		Hostname = hostname
	}

	if BestInterface >= 0 {
		MAC = Interfaces[BestInterface].Interface.HardwareAddr.String()
		if !strings.HasPrefix(Interfaces[BestInterface].Hostname, "ERROR!") {
			Hostname = Interfaces[BestInterface].Hostname
		}
		if !strings.HasPrefix(Interfaces[BestInterface].Domain, "ERROR!") {
			Domain = Interfaces[BestInterface].Domain
		}
		if !strings.HasPrefix(Interfaces[BestInterface].IP, "ERROR!") {
			IP = Interfaces[BestInterface].IP
		}
		ServerSourceAddress = IP + ServerListenAddress[strings.Index(ServerListenAddress, ":"):]
	}

	util.Log(1, "INFO! Hostname: %v  Domain: %v  MAC: %v  Listener: %v", Hostname, Domain, MAC, ServerSourceAddress)

	if PreferredServer != "" {
		pref, err := util.Resolve(PreferredServer, IP)
		if err != nil {
			util.Log(0, "ERROR! Could not resolve [server]/ip value \"%v\": %v", PreferredServer, err)
			PreferredServer = ""
		} else {
			PreferredServer = pref
		}
	}

	for _, srv := range Interfaces[BestInterface].Peers {
		ServerNamesFromSRVRecords = append(ServerNamesFromSRVRecords, srv.Target)
	}
}

// Returns the gosa-si servers listed in DNS.
func ServersFromDNS() []string {
	var cname string
	var addrs []*net.SRV
	cname, addrs, err := net.LookupSRV("gosa-si", "tcp", Domain)
	if err != nil {
		util.Log(1, "INFO! LookupSRV: %v", err)
		return []string{}
	}

	servers := make([]string, len(addrs))
	if len(addrs) == 0 {
		util.Log(1, "INFO! No other go-susi or gosa-si servers listed in DNS for domain '%v'", Domain)
	} else {
		for i := range addrs {
			servers[i] = fmt.Sprintf("%v:%v", strings.TrimRight(addrs[i].Target, "."), addrs[i].Port)
		}
		util.Log(1, "INFO! DNS lists the following %v servers: %v", cname, strings.Join(servers, ", "))
	}
	return servers
}

// Constructs a standard environment for hook execution and returns it.
func HookEnvironment() []string {
	env := []string{"MAC=" + MAC, "IPADDRESS=" + IP, "SERVERPORT=" + ServerListenAddress[strings.Index(ServerListenAddress, ":")+1:],
		"HOSTNAME=" + Hostname, "FQDN=" + Hostname + "." + Domain}
	return env
}

func Shutdown() {
	util.Log(1, "INFO! Removing temporary directory %v", TempDir)
	err := os.RemoveAll(TempDir)
	if err != nil {
		util.Log(0, "ERROR! Could not remove temporary directory: %v", err)
	}
}
Beispiel #9
0
// Infinite loop that handles registering and staying registered at
// a server.
func RegistrationHandler() {
	registrationQueue.Push("register")

	for {
		rn := registrationQueue.Next()
		var r string
		switch rn := rn.(type) {
		case string:
			r = rn
		case *xml.Hash:
			server := rn.Text("source")
			if rn.Text("header") == "deregistered" {
				if server != currentServer {
					continue // ignore deregistered from servers we don't want to be registered at
				}
				util.Log(1, "INFO! Received \"deregistered\" => Confirming that I'm still registered at %v", currentServer)
				r = "confirm"
			} else {
				r = server
			}
		case chan string:
			if registrationState > 0 {
				rn <- currentServer
			} else {
				rn <- ""
			}
			continue
		default:
			panic("RegistrationHandler(): Unexpected type in registrationQueue")
		}

		switch r {
		case "register":
			if registrationState == 0 {
				serverList = serversToTry()
				currentServer = "" // AFTER serversToTry() because it uses currentServer
				util.Log(1, "INFO! New server registration started. Preferred server: %v  Candidates: %v", config.PreferredServer, serverList)
				indexInList = -1
				registrationQueue.Push("timeout")
			}
		case "confirm_timeout":
			if registrationState == 1 {
				util.Log(0, "WARNING! Could not confirm that I'm still registered at %v => Start new registration", currentServer)
				registrationState = 0
				registrationQueue.Push("register")
			}
		case "timeout":
			if registrationState == 0 {
				for indexInList++; indexInList < len(serverList) && serverList[indexInList] == ""; indexInList++ {
				}
				if indexInList < len(serverList) {
					if currentServer != "" {
						util.Log(0, "WARNING! Registration at %v failed => Will try next candidate server", currentServer)
					}
					currentServer, _ = util.Resolve(serverList[indexInList], config.IP)
					util.Log(1, "INFO! Trying to register at %v", currentServer)
					go Send_here_i_am(currentServer)
					go func() {
						delay := time.Duration(secs_between_candidates+rand.Intn(10)) * time.Second
						if len(serverList) == 1 { // if we have only 1 candidate, use the longer confirmation timeout
							delay = timeout_for_confirmation
						}
						time.Sleep(delay)
						registrationQueue.Push("timeout")
					}()
				} else {
					util.Log(0, "WARNING! Registration failed. No more servers left to try. Will wait 1 minute then try again.")
					// wait with random element to disband any client swarms
					time.Sleep(time.Duration(55+rand.Intn(20)) * time.Second)
					registrationQueue.Insert("register")
				}
			}
		case currentServer:
			if registrationState != 2 {
				util.Log(1, "INFO! Successfully registered at %v", currentServer)
				registrationState = 2
				go CallRegisteredHook(rn.(*xml.Hash))
			}

		case "confirm":
			if registrationState == 2 {
				registrationState = 1
				go Send_here_i_am(currentServer)
				go func() {
					time.Sleep(timeout_for_confirmation)
					registrationQueue.Push("confirm_timeout")
				}()
			}

		default:
			util.Log(0, "WARNING! Received \"registered\" from unexpected server %v => Confirming that I'm still registered at %v", r, currentServer)
			registrationQueue.Push("confirm")
		}
	}
}
Beispiel #10
0
// Unit tests for the package github.com/mbenkmann/golib/util.
func Util_test() {
	fmt.Printf("\n==== util ===\n\n")

	addr, err := util.Resolve("1.2.3.4", "")
	check(err, nil)
	check(addr, "1.2.3.4")

	addr, err = util.Resolve("1.2.3.4:5", "")
	check(err, nil)
	check(addr, "1.2.3.4:5")

	addr, err = util.Resolve("::1:5", "")
	check(err, nil)
	check(addr, "[::1:5]")

	addr, err = util.Resolve("localhost:65535", "")
	check(err, nil)
	check(addr, "127.0.0.1:65535")

	addr, err = util.Resolve("localhost", "")
	check(err, nil)
	check(addr, "127.0.0.1")

	addr, err = util.Resolve("::1", "")
	check(err, nil)
	check(addr, "127.0.0.1")

	addr, err = util.Resolve("[::1]", "")
	check(err, nil)
	check(addr, "127.0.0.1")

	addr, err = util.Resolve("[::1]:12345", "")
	check(err, nil)
	check(addr, "127.0.0.1:12345")

	addr, err = util.Resolve("localhost:65535", "foo")
	check(err, nil)
	check(addr, "foo:65535")

	addr, err = util.Resolve("localhost", "foo")
	check(err, nil)
	check(addr, "foo")

	addr, err = util.Resolve("::1", "foo")
	check(err, nil)
	check(addr, "foo")

	addr, err = util.Resolve("[::1]", "foo")
	check(err, nil)
	check(addr, "foo")

	addr, err = util.Resolve("[::1]:12345", "foo")
	check(err, nil)
	check(addr, "foo:12345")

	addr, err = util.Resolve("", "")
	check(hasWords(err, "no", "such", "host"), "")
	check(addr, "")

	addr, err = util.Resolve(":10", "")
	check(hasWords(err, "no", "such", "host"), "")
	check(addr, ":10")

	check(util.WaitForDNS(3*time.Second), true)

	h, _ := exec.Command("hostname").CombinedOutput()
	hostname := strings.TrimSpace(string(h))

	ipp, _ := exec.Command("hostname", "-I").CombinedOutput()
	ips := strings.Fields(strings.TrimSpace(string(ipp)))
	addr, err = util.Resolve(hostname+":234", config.IP)
	check(err, nil)
	ip := ""
	for _, ip2 := range ips {
		if addr == ip2+":234" {
			ip = ip2
		}
	}
	check(addr, ip+":234")

	testLogging()

	buf := make([]byte, 80)
	for i := range buf {
		buf[i] = byte(util_test_rng.Intn(26) + 'a')
	}

	crap1 := &crappyConnection1{}
	n, err := util.WriteAll(crap1, buf)
	check(string(*crap1), string(buf))
	check(n, len(buf))
	check(err, nil)

	crap2 := &crappyConnection2{}
	n, err = util.WriteAll(crap2, buf)
	check(string(*crap2), string(buf))
	check(n, len(buf))
	check(err, nil)

	stalled1 := &stalledConnection1{}
	n, err = util.WriteAll(stalled1, buf)
	check(string(*stalled1), string(buf[0:16]))
	check(n, 16)
	check(err, io.ErrShortWrite)

	stalled2 := &stalledConnection2{}
	n, err = util.WriteAll(stalled2, buf)
	check(string(*stalled2), string(buf[0:16]))
	check(n, 16)
	check(err, io.ErrShortWrite)

	broken := &brokenConnection{}
	n, err = util.WriteAll(broken, buf)
	check(string(*broken), string(buf[0:16]))
	check(n, 16)
	check(err, io.ErrClosedPipe)

	panicker := func() {
		foobar = "bar"
		panic("foo")
	}

	var buffy bytes.Buffer
	util.LoggersSuspend()
	util.LoggerAdd(&buffy)
	defer util.LoggersRestore()

	util.WithPanicHandler(panicker)
	time.Sleep(200 * time.Millisecond) // make sure log message is written out
	check(foobar, "bar")
	check(len(buffy.String()) > 10, true)

	listener, err := net.Listen("tcp", "127.0.0.1:39390")
	if err != nil {
		panic(err)
	}

	go func() {
		r, err := listener.Accept()
		if err != nil {
			panic(err)
		}
		buf := make([]byte, 1)
		r.Read(buf)
		time.Sleep(10 * time.Second)
		r.Read(buf)
	}()
	long := make([]byte, 10000000)
	longstr := string(long)
	buffy.Reset()
	t0 := time.Now()
	util.SendLnTo("127.0.0.1:39390", longstr, 5*time.Second)
	duration := time.Since(t0)
	check(duration > 4*time.Second && duration < 6*time.Second, true)
	time.Sleep(200 * time.Millisecond) // make sure log message is written out
	check(strings.Contains(buffy.String(), "ERROR"), true)

	go func() {
		conn, err := listener.Accept()
		if err != nil {
			panic(err)
		}
		ioutil.ReadAll(conn)
	}()
	long = make([]byte, 10000000)
	longstr = string(long)
	buffy.Reset()
	t0 = time.Now()
	util.SendLnTo("127.0.0.1:39390", longstr, 5*time.Second)
	duration = time.Since(t0)
	check(duration < 2*time.Second, true)
	time.Sleep(200 * time.Millisecond) // make sure log message is written out
	check(buffy.String(), "")

	// Test that ReadLn() times out properly
	go func() {
		_, err := net.Dial("tcp", "127.0.0.1:39390")
		if err != nil {
			panic(err)
		}
	}()
	conn, err := listener.Accept()
	if err != nil {
		panic(err)
	}
	t0 = time.Now()
	st, err := util.ReadLn(conn, 5*time.Second)
	duration = time.Since(t0)
	check(duration > 4*time.Second && duration < 6*time.Second, true)
	check(st, "")
	check(hasWords(err, "timeout"), "")

	// Test that ReadLn() returns io.EOF if last line not terminated by \n
	go func() {
		conn, err := net.Dial("tcp", "127.0.0.1:39390")
		if err != nil {
			panic(err)
		}
		conn.Write([]byte("foo\r"))
		conn.Close()
	}()
	conn, err = listener.Accept()
	if err != nil {
		panic(err)
	}
	st, err = util.ReadLn(conn, 5*time.Second)
	check(err, io.EOF)
	check(st, "foo")

	go func() {
		conn, err := net.Dial("tcp", "127.0.0.1:39390")
		if err != nil {
			panic(err)
		}
		conn.Write([]byte("\r\r\n\rfo\ro\nbar\r\nfoxtrott"))
		conn.Close()
	}()
	conn, err = listener.Accept()
	if err != nil {
		panic(err)
	}
	// Test proper trimming of multiple \r
	st, err = util.ReadLn(conn, 0)
	check(err, nil)
	check(st, "")
	// Test that the empty first line has actually been read
	// and that the next ReadLn() reads the 2nd line
	// Also test that negative timeouts work the same as timeout==0
	// Also test that \r is not trimmed at start and within line.
	st, err = util.ReadLn(conn, -1*time.Second)
	check(err, nil)
	check(st, "\rfo\ro")
	// Check 3rd line
	st, err = util.ReadLn(conn, 0)
	check(err, nil)
	check(st, "bar")
	// Check 4th line and io.EOF error
	st, err = util.ReadLn(conn, 0)
	check(err, io.EOF)
	check(st, "foxtrott")

	// Test that delayed reads work with timeout==0
	go func() {
		conn, err := net.Dial("tcp", "127.0.0.1:39390")
		if err != nil {
			panic(err)
		}
		time.Sleep(1 * time.Second)
		_, err = conn.Write([]byte("foo\r\n"))
		if err != nil {
			panic(err)
		}
		time.Sleep(2 * time.Second)
	}()
	conn, err = listener.Accept()
	if err != nil {
		panic(err)
	}
	t0 = time.Now()
	st, err = util.ReadLn(conn, time.Duration(0))
	duration = time.Since(t0)
	check(duration < 2*time.Second, true)
	check(duration > 800*time.Millisecond, true)
	check(err, nil)
	check(st, "foo")

	counter := util.Counter(13)
	var b1 UintArray = make([]uint64, 100)
	var b2 UintArray = make([]uint64, 100)
	done := make(chan bool)
	fill := func(b UintArray) {
		for i := 0; i < 100; i++ {
			b[i] = <-counter
			time.Sleep(1 * time.Millisecond)
		}
		done <- true
	}
	go fill(b1)
	go fill(b2)
	<-done
	<-done
	check(sort.IsSorted(&b1), true)
	check(sort.IsSorted(&b2), true)
	var b3 UintArray = make([]uint64, 200)
	i := 0
	j := 0
	k := 0
	for i < 100 || j < 100 {
		if i == 100 {
			b3[k] = b2[j]
			j++
			k++
			continue
		}
		if j == 100 {
			b3[k] = b1[i]
			i++
			k++
			continue
		}
		if b1[i] == b2[j] {
			check(b1[i] != b2[j], true)
			break
		}
		if b1[i] < b2[j] {
			b3[k] = b1[i]
			i++
		} else {
			b3[k] = b2[j]
			j++
		}
		k++
	}

	one_streak := true
	b5 := make([]uint64, 200)
	for i := 0; i < 200; i++ {
		if i < 100 && b1[i] != uint64(13+i) && b2[i] != uint64(13+i) {
			one_streak = false
		}
		b5[i] = uint64(13 + i)
	}

	check(b3, b5)
	check(one_streak, false) // Check whether goroutines were actually executed concurrently rather than in sequence

	tempdir, err := ioutil.TempDir("", "util-test-")
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(tempdir)
	fpath := tempdir + "/foo.log"
	logfile := util.LogFile(fpath)
	check(logfile.Close(), nil)
	n, err = util.WriteAll(logfile, []byte("Test"))
	check(err, nil)
	check(n, 4)
	check(logfile.Close(), nil)
	n, err = util.WriteAll(logfile, []byte("12"))
	check(err, nil)
	check(n, 2)
	n, err = util.WriteAll(logfile, []byte("3"))
	check(err, nil)
	check(n, 1)
	check(os.Rename(fpath, fpath+".old"), nil)
	n, err = util.WriteAll(logfile, []byte("Fo"))
	check(err, nil)
	check(n, 2)
	f2, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
	f2.Write([]byte("o"))
	f2.Close()
	n, err = util.WriteAll(logfile, []byte("bar"))
	check(err, nil)
	check(n, 3)
	check(logfile.Close(), nil)
	data, err := ioutil.ReadFile(fpath)
	check(err, nil)
	if err == nil {
		check(string(data), "Foobar")
	}
	data, err = ioutil.ReadFile(fpath + ".old")
	check(err, nil)
	if err == nil {
		check(string(data), "Test123")
	}

	test_time := time.Date(2013, time.January, 20, 14, 7, 21, 0, time.Local)
	check(util.MakeTimestamp(test_time), "20130120140721")
	test_time = time.Date(2013, time.January, 20, 14, 7, 21, 0, time.UTC)
	check(util.MakeTimestamp(test_time), "20130120140721")
	test_time = time.Date(2013, time.January, 20, 14, 7, 21, 0, time.FixedZone("Fooistan", 45678))
	check(util.MakeTimestamp(test_time), "20130120140721")
	illegal := time.Unix(0, 0)
	buffy.Reset()
	check(util.ParseTimestamp(""), illegal)
	time.Sleep(200 * time.Millisecond) // make sure log message is written out
	check(strings.Contains(buffy.String(), "ERROR"), true)
	buffy.Reset()
	check(util.ParseTimestamp("20139910101010"), illegal)
	time.Sleep(200 * time.Millisecond) // make sure log message is written out
	check(strings.Contains(buffy.String(), "ERROR"), true)
	check(util.ParseTimestamp("20131110121314"), time.Date(2013, time.November, 10, 12, 13, 14, 0, time.Local))
	check(util.MakeTimestamp(util.ParseTimestamp(util.MakeTimestamp(test_time))), util.MakeTimestamp(test_time))
	test_time = test_time.Add(2400 * time.Hour)
	check(util.MakeTimestamp(util.ParseTimestamp(util.MakeTimestamp(test_time))), util.MakeTimestamp(test_time))
	test_time = test_time.Add(2400 * time.Hour)
	check(util.MakeTimestamp(util.ParseTimestamp(util.MakeTimestamp(test_time))), util.MakeTimestamp(test_time))
	test_time = test_time.Add(2400 * time.Hour)
	check(util.MakeTimestamp(util.ParseTimestamp(util.MakeTimestamp(test_time))), util.MakeTimestamp(test_time))
	test_time = test_time.Add(2400 * time.Hour)
	check(util.MakeTimestamp(util.ParseTimestamp(util.MakeTimestamp(test_time))), util.MakeTimestamp(test_time))

	diff := time.Since(util.ParseTimestamp(util.MakeTimestamp(time.Now())))
	if diff < time.Second {
		diff = 0
	}
	check(diff, time.Duration(0))

	t0 = time.Now()
	util.WaitUntil(t0.Add(-10 * time.Second))
	util.WaitUntil(t0.Add(-100 * time.Minute))
	dur := time.Now().Sub(t0)
	if dur < 1*time.Second {
		dur = 0
	}
	check(dur, 0)
	t0 = time.Now()
	util.WaitUntil(t0.Add(1200 * time.Millisecond))
	dur = time.Now().Sub(t0)
	if dur >= 1200*time.Millisecond && dur <= 1300*time.Millisecond {
		dur = 1200 * time.Millisecond
	}
	check(dur, 1200*time.Millisecond)

	mess := "WaitUntil(Jesus first birthday) takes forever"
	go func() {
		util.WaitUntil(time.Date(1, time.December, 25, 0, 0, 0, 0, time.UTC))
		mess = ""
	}()
	time.Sleep(100 * time.Millisecond)
	check(mess, "")

	mess = "WaitUntil(1000-11-10 00:00:00) takes forever"
	go func() {
		util.WaitUntil(time.Date(1000, time.October, 11, 0, 0, 0, 0, time.UTC))
		mess = ""
	}()
	time.Sleep(100 * time.Millisecond)
	check(mess, "")

	testBase64()
}
Beispiel #11
0
func GosaPing(macaddress string) bool {
	portscan := false
	target := ""
	if system := db.ClientWithMAC(macaddress); system != nil {
		target = system.Text("client")
	} else if system := db.ServerWithMAC(macaddress); system != nil {
		target = system.Text("source")
	} else if system := db.SystemFullyQualifiedNameForMAC(macaddress); system != "none" {
		addr, err := util.Resolve(system, config.IP)
		if err == nil {
			target = addr
			portscan = true
		}
	}

	if target == "" {
		util.Log(0, "ERROR! gosa_ping can't determine IP for MAC \"%v\"", macaddress)
		return false
	}

	reachable := make(chan bool, 2)

	if portscan {
		// Scan ports sequentially in one goroutine.
		// This gives a fast reachable<-false if the network reports that all
		// ports are unreachable. It may be slow, however, if the network simply
		// DROPs request packages for closed ports.
		// For this reason, see further below...
		go func() {
			for _, port := range config.ClientPorts {
				conn, err := net.Dial("tcp", target+":"+port)
				if err == nil {
					conn.Close()
					reachable <- true
					return
				}
			}
			reachable <- false
		}()

		// ... Scan the same ports in parallel. This gives a fast reachable<-true if
		// at least one port is reachable.
		for _, port := range config.ClientPorts {
			go func(p string) {
				conn, err := net.Dial("tcp", target+":"+p)
				if err == nil {
					conn.Close()
					reachable <- true
					return
				}
			}(port)
		}
	} else { // no portscan necessary. Use target directly.
		go func() {
			conn, err := net.Dial("tcp", target)
			if err != nil {
				reachable <- false
			} else {
				conn.Close()
				reachable <- true
			}
		}()
	}

	// Make sure we don't wait too long for a result.
	go func() {
		time.Sleep(100 * time.Millisecond)
		reachable <- false
	}()

	if <-reachable {
		util.Log(1, "INFO! gosa_ping says client %v/%v is ON", macaddress, target)
		return true
	}

	util.Log(1, "INFO! gosa_ping says client %v/%v is OFF", macaddress, target)
	return false
}