Dev (Back & Front)ARTIGO

Como descobrir o ip do cliente e do servidor usando Golang

Recentemente eu precisava subir um pequeno serviço REST para gerenciar alguns hardwares, sem contato humano e com interfaces de rede. A solução? Golang.

Como descobrir o ip do cliente e do servidor usando Golang
Imagem: Cesar Gimenes

Recentemente eu esbarrei com um problema interessante, eu precisava subir um pequeno serviço REST para gerenciar alguns hardwares, tudo sem contato humano e também com várias interfaces de rede.

Leia aqui o artigo original

Em um determinado momento meu sistema tem que subir um serviço auxiliar e informar o cliente em que ip e porta ele deveria acessar. Normalmente isso seria feito com um arquivo de configuração em algum lugar, mas um requisito é que eu não podia presumir meu ip porque ele poderia vir de qualquer uma das interfaces de rede e deixar tudo isso parametrizado ficaria complexo demais.

A solução foi automatizar todo o processo dentro do meu próprio código e para isso eu precisava saber tanto meu ip como o do cliente, assim eu saberia qual rede responder e etc.

Como o Go tem uma biblioteca net muito boa eu também já queria dar suporte para ipv6, isso não é difícil, basicamente é só tomar cuidado para usar as coisas que o Go fornece e não presumir o formato do ip e porta.

Tratando IP

Existem duas funções do pacote net que não são exportadas então eu copiei elas para meu código para ajudar a parsear o resultado.

A função last serve para extrair a ultima parte de uma string dado um separador, no caso estamos usando para extrair a zona em endereços ipv6, a zona geralmente é o nome da interface de rede.

csharp
func last(s string, b byte) int {
	i := len(s)
	for i--; i >= 0; i-- {
		if s[i] == b {
			break
		}
	}
	return i
}

A função splitHostZone retorna o host e a zona separados se não tiver zona ela sera uma string vazia, eu preciso disso porque quando eu juntar o ip com a porta novamente eu não quero incluir a zona.

csharp
func splitHostZone(s string) (host, zone string) {
	// The ipv6 scoped addressing zone identifier starts after the
	// last percent sign.
	if i := last(s, '%'); i > 0 {
		host, zone = s[:i], s[i+1:]
		return
	}
	host = s
	return
}

Pegando o ip do servidor

Para descobrir o ip do servidor tem varias formas mas a mais simples e no “estilo go” que eu encontrei foi pegando o endereço que é colocado no contexto da requisição.

csharp
adr := r.Context().Value(http.LocalAddrContextKey)
serverAddr, serverPort, err := net.SplitHostPort(
	fmt.Sprintf("%v", adr))
if err != nil {
	fmt.Println(err)
	return
}
serverIP, serverZone := splitHostZone(serverAddr)

Para pegar o ip do cliente é mais tranquilo porque isso já vem na requisição então é só tratar o retorno como fizemos antes.

csharp
clientAddr, clientPort, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
	fmt.Println(err)
	return
}
clientIP, clientZone := splitHostZone(clientAddr)

Aqui tem um gist com o código do exemplo.

Cesar GimenesAutor

Trabalha com tecnologia desde a década de 90. Já atuou na área de educação e participou de projetos de mobilidade de grande volume para laboratórios farmacêuticos. Criou games tanto para PC, como para iOS. Hoje está direcionando seus esforços em plataformas de Sistemas Embarcados, IoT, microservices e cloud computing. É um entusiasta de tecnologias como Golang e Docker.

Ver perfil