unifi icon indicating copy to clipboard operation
unifi copied to clipboard

How i can get data from devices connected to ports (Principally MAC address) from a Switch

Open pablofloreswittich opened this issue 3 years ago • 5 comments

I am trying to get data from all devices (Clientes, APs, USW, Gateways) connected to ports (Principally MAC address) I am itereting each port but the mac is empty (it shows a blank space) in unifi controller webpage it shows the MAC, but i can't get it with the unpoller can u help me?

Here is my code and output: image image

pablofloreswittich avatar Sep 22 '21 13:09 pablofloreswittich

That's a picture of code, not actually code. It's also missing portions, so no one can use that to reproduce your behavior. Here's the same answer I provided on Discord before you posted this:

I'm not seeing anywhere in the code that messes with client mac addresses nor the mac addresses in the port tables. I suspect the API is not providing them. I get the same result as you. The example in the repo shows how to loop each client. You can get the switch MAC and client MAC there.

This library just pulls the API data from your controller. I recommend pulling that data directly (curl), yourself, and inspecting it, so you know what's available.

davidnewhall avatar Sep 22 '21 19:09 davidnewhall

package main

import (
	"fmt"
	"log"

	"github.com/unpoller/unifi"
)

type paquete struct {
	CPU                string
	Mem                string
	GeneralTemperature string
	Uptime             string
	FanLevel           string
	MemTotal           string
	MemUsed            string
	MemAverage         string
	Ip                 string
	MAC                int
	Model              int
	Name               int
	Overheating        int
	TxBytes            int
	UpTime             int
	Version            int
	//aca falta todas las mac conectadas al switch
}

func main() {
	c := unifi.Config{
		User: "***@gmail.com",
		Pass: "***",
		URL:  "https://127.0.0.1:8443/",
		// Log with log.Printf or make your own interface that accepts (msg, fmt)
		ErrorLog: log.Printf,
		DebugLog: log.Printf,
	}
	uni, err := unifi.NewUnifi(&c)
	if err != nil {
		log.Fatalln("Error:", err)
	}

	sites, err := uni.GetSites()
	if err != nil {
		log.Fatalln("Error:", err)
	}
	clients, err := uni.GetClients(sites)
	if err != nil {
		log.Fatalln("Error:", err)
	}
	devices, err := uni.GetDevices(sites)
	if err != nil {
		log.Fatalln("Error:", err)
	}

	alarmas, err := uni.GetAlarms(sites)
	if err != nil {
		log.Fatalln("Error:", err)
	}
	/*
		anos, err := uni.GetAnomalies(sites)
		if err != nil {
			log.Fatalln("Error:", err)
		} */

	log.Println(devices.USWs[0].SystemStats.CPU, "    CPU")
	log.Println(devices.USWs[0].SystemStats.Mem, "    Mem")
	log.Println(devices.USWs[0].GeneralTemperature, "    GeneralTemperature")
	log.Println(devices.USWs[0].SystemStats.Uptime, "    Uptime")
	log.Println(devices.USWs[0].FanLevel, "    FanLevel")
	log.Println(devices.USWs[0].SysStats.MemTotal.Val, "    MemTotal")
	log.Println(devices.USWs[0].SysStats.MemUsed.Val, "    MemUsed")
	log.Println(int((float32(devices.USWs[0].SysStats.MemUsed.Val)/float32(devices.USWs[0].SysStats.MemTotal.Val))*100), "    MemAverage")
	log.Println(devices.USWs[0].ID, "    Id")
	log.Println(devices.USWs[0].IP, "    Ip")
	log.Println(devices.USWs[0].Mac, "    MAC")
	log.Println(devices.USWs[0].Model, "    Model")
	log.Println(devices.USWs[0].Name, "    Name")
	log.Println(devices.USWs[0].Overheating, "    Overheating")
	log.Println(devices.USWs[0].TxBytes, "    TxBytes")
	log.Println(devices.USWs[0].Uptime, "    UpTime")
	log.Println(devices.USWs[0].Version, "    Version")

	log.Println(len(devices.USWs), "Unifi Switches Found")
	log.Println(devices.USWs[0].Model, "    Model")
	log.Println(devices.USWs[0].Name, "    Name")
	for i := 0; i < 26; i++ {
		log.Println(devices.USWs[0].PortTable[i].Name)
		log.Println(devices.USWs[0].PortTable[i].Mac)
	}

	log.Println(len(devices.USGs), "Unifi Gateways Found")

	log.Println(len(devices.UAPs), "Unifi Wireless APs Found:")
	for i, uap := range devices.UAPs {
		log.Println(i+1, uap.Name, uap.IP)
	}

	log.Println(alarmas[0])
	log.Println(len(alarmas), "Alarmas. ")
	for i := 0; i < len(alarmas); i++ {
		fmt.Println("")
		log.Println("Evento ", i+1, ": ", alarmas[i].Key)
		log.Println("Mensaje ", i+1, ": ", alarmas[i].Msg)
		log.Println("Fecha ", i+1, ": ", alarmas[i].Datetime)
		fmt.Println("")

	}

	for i := 0; i < len(clients); i++ {
		/* log.Println(clients[i].Mac) */
		log.Println(clients[i].SwPort)
		log.Println(clients[i].Mac)
	}

	for i := 0; i < len(clients); i++ {
		/* log.Println(clients[i].Mac) */
		log.Println(clients[i].SwPort)
		log.Println(clients[i].Mac)
	}

	log.Println("-----------------------------------------------------------------------")

	log.Println(len(clients), "Clients connected:")
	for i, client := range clients {
		log.Println(i+1, client.SwPort.Val, client.Mac, client.IP, client.SwMac)
	}

	log.Println(len(devices.UAPs), "AP Connected:")
	for i, ap := range devices.UAPs {
		log.Println(i+1, ap.Mac, ap.Model, ap.PortTable)
	}
}

pablofloreswittich avatar Sep 22 '21 19:09 pablofloreswittich

This is the code, thank you very much for your help, how do I do what you told me? ( pulling all data directly)

pablofloreswittich avatar Sep 22 '21 19:09 pablofloreswittich

You can use cURL to pull the data, the API endpoint links are in types.go, the device endpoint you're looking for is here: https://github.com/unpoller/unifi/blob/82e0d2cb4da1a28e0e057cc36dca38f5bd9ced56/types.go#L36

So if you wanted to pull from curl, you could go to the page in your browser, select a request to the API, select copy as curl and then tweak it a bit.

For example:

 curl 'https://127.0.0.18443/api/s/default/stat/device' -H 'User-Agent: Foo' -H 'Accept: application/json, text/plain, */*' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br' -H 'Referer: https://127.0.0.1:8443/manage/default/clients' -H 'X-Csrf-Token: <a token here>' -H 'Connection: keep-alive' -H 'Cookie: unifises=<a cookie here>' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -o - | gunzip

the -o - | gunzip does two things, one sends data to your terminal, then pipes it to gunzip, which is important since we're asking for gzip encoding (compressed data)

Now, the actual output of this endpoint does not contain the data you're looking for:

"port_table":
            [
                {
                    "aggregated_by": "<SOME VALUE/>",
                    "autoneg": "<SOME VALUE/>",
                    "bytes-r": "<SOME VALUE/>",
                    "enable": "<SOME VALUE/>",
                    "flowctrl_rx": "<SOME VALUE/>",
                    "flowctrl_tx": "<SOME VALUE/>",
                    "full_duplex": "<SOME VALUE/>",
                    "is_uplink": "<SOME VALUE/>",
                    "jumbo": "<SOME VALUE/>",
                    "masked": "<SOME VALUE/>",
                    "media": "<SOME VALUE/>",
                    "name": "Port <SOME VALUE/>",
                    "op_mode": "<SOME VALUE/>",
                    "port_idx": "<SOME VALUE/>",
                    "port_poe": "<SOME VALUE/>",
                    "portconf_id": "<SOME VALUE/>",
                    "rx_broadcast": "<SOME VALUE/>",
                    "rx_bytes": "<SOME VALUE/>",
                    "rx_bytes-r": "<SOME VALUE/>",
                    "rx_dropped": "<SOME VALUE/>",
                    "rx_errors": "<SOME VALUE/>",
                    "rx_multicast": "<SOME VALUE/>",
                    "rx_packets": "<SOME VALUE/>",
                    "speed": "<SOME VALUE/>",
                    "speed_caps": "<SOME VALUE/>",
                    "tx_broadcast": "<SOME VALUE/>",
                    "tx_bytes": "<SOME VALUE/>",
                    "tx_bytes-r": "<SOME VALUE/>",
                    "tx_dropped": "<SOME VALUE/>",
                    "tx_errors": "<SOME VALUE/>",
                    "tx_multicast": "<SOME VALUE/>",
                    "tx_packets": "<SOME VALUE/>",
                    "up": "<SOME VALUE/>",
                },

This is coming from a controller v6.5.55

To get the mapping you want, you'll need to combine the above data with the data from GetClients. If it's wireless it could have both a ap_mac and sw_mac, wired clients should only have sw_mac. They also have a sw_port, you can then do a reverse lookup, or build a map of devices by their mac, and print the info you want.

wade-p avatar Jan 08 '22 14:01 wade-p

This is the code, thank you very much for your help, how do I do what you told me? ( pulling all data directly)

Sorry I missed your question. Thank you to @wade-p for the detailed answer.

You can also run unifi-poller -c config.file -j d to print out devices, and unifi-poller -c config.file -j c to print out clients. This is a direct JSON dump from the controller as curl would do it. You just need to have a config file with your unifi username and password in it, so poller can handle the login and cookies.

And if you want to pull data from an arbitrary API path, use this syntax:

unifi-poller -c config.file -j "other /api/path"

Like so unifi-poller -c /etc/unifi-poller/up.conf -j "other /api/s/default/list/alarm"

davidnewhall avatar Jan 08 '22 20:01 davidnewhall

this looks solved, closing this 👍

platinummonkey avatar Dec 12 '22 22:12 platinummonkey