MAC vendor lookup: Difference between revisions
(→{{header|Perl}}: Add request throttling.) |
(→{{header|APL}}: formatting.) |
||
Line 80: | Line 80: | ||
⍝ parameter which we call macList, and the value of the local variable |
⍝ parameter which we call macList, and the value of the local variable |
||
⍝ vendors will become the function's return value |
⍝ vendors will become the function's return value |
||
∇ vendors ← vendorLookup macList |
∇ vendors ← vendorLookup macList |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⍝ end function definition |
|||
∇ |
∇ |
||
Revision as of 16:16, 31 July 2022
You are encouraged to solve this task according to the task description, using any language you may know.
Every connected device around the world comes with a unique Media Access Control address, or a MAC address.
A common task a network administrator may come across is being able to identify a network device's manufacturer when given only a MAC address.
- Task
Interface with one (or numerous) APIs that exist on the internet and retrieve the device manufacturer based on a supplied MAC address.
A MAC address that does not return a valid result should return the String "N/A". An error related to the network connectivity or the API should return a null result.
Many implementations on this page use http://api.macvendors.com/ which, as of 19th September 2021, is throttling requests. After only 2 calls, the following response is returned for all subsequent requests. If you are planning to use the same provider or going to run the examples on this page, consider building in a delay between two calls.
{"errors":{"detail":"Too Many Requests","message":"Please slow down your requests or upgrade your plan at https://macvendors.com"}}
Ada
<lang Ada>with Ada.Text_IO;
with AWS.Client; with AWS.Response; with AWS.Messages;
procedure MAC_Vendor is
procedure Lookup (MAC : in String) is use AWS.Response; use AWS.Messages; URL : constant String := "http://api.macvendors.com/" & MAC; Page : constant Data := AWS.Client.Get (URL); use Ada.Text_IO; begin Put (MAC); Set_Col (20); case AWS.Response.Status_Code (Page) is when S200 => Put_Line (Message_Body (Page)); when S404 => Put_Line ("N/A"); when others => Put_Line ("Error"); end case; end Lookup;
begin
-- Have to throttle traffic to site Lookup ("88:53:2E:67:07:BE"); delay 1.500; Lookup ("D4:F4:6F:C9:EF:8D"); delay 1.500; Lookup ("FC:FB:FB:01:FA:21"); delay 1.500; Lookup ("4c:72:b9:56:fe:bc"); delay 1.500; Lookup ("00-14-22-01-23-45"); delay 1.500; Lookup ("23-45-67"); delay 1.500; Lookup ("foobar");
end MAC_Vendor;</lang>
- Output:
88:53:2E:67:07:BE Intel Corporate D4:F4:6F:C9:EF:8D Apple, Inc. FC:FB:FB:01:FA:21 Cisco Systems, Inc 4c:72:b9:56:fe:bc PEGATRON CORPORATION 00-14-22-01-23-45 Dell Inc. 23-45-67 N/A foobar N/A
APL
Normally something like this would just be mapping the lookup across an array, but that doesn't let us control the timing of the request dispatch. To insert a delay between requests we have to create a traditional function ("tradfn") with a for loop.
<lang apl>⍝load the library module ]load HttpCommand
⍝ define a direct function (dfn) to look up a single MAC address vendorLookup1 ← { (HttpCommand.Get 'http://api.macvendors.com/',⍕⍵).Data }
⍝ define a traditional function to look up all the MAC addresses in a list with ⍝ a delay between calls
⍝ The header says that the function is named vendorLookup, it takes a single ⍝ parameter which we call macList, and the value of the local variable ⍝ vendors will become the function's return value ∇ vendors ← vendorLookup macList
⍝ look up the first vendor and put it into an array in our return var vendors ← ⊆vendorLookup1 macList[1] ⍝ Loop over the rest of the array (1↓ removes the first item) :For burger :In 1↓macList ⎕DL 2 ⍝ wait 2 seconds vendors ⍪← ⊆vendorLookup1 burger ⍝ then look up the next vendor and append :EndFor
∇
⍝ demo data macList ← '88:53:2E:67:07:BE' 'D4:F4:6F:C9:EF:8D' 'FC:FB:FB:01:FA:21' macList ⍪← '4c:72:b9:56:fe:bc' '00-14-22-01-23-45'
⍝ look up the vendors (takes a while with the 2-second delay between lookups) vendorList ← vendorLookup macList
⍝ the result is an array (a 1-row by N-column matrix). to print out one vendor ⍝ per line, we reshape it to be N rows by 1 column instead. ⎕←(⍴ vendorList)[1] 1 ⍴ vendorList</lang>
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
AppleScript
<lang AppleScript>set apiRoot to "https://api.macvendors.com" set macList to {"88:53:2E:67:07:BE", "D4:F4:6F:C9:EF:8D", ¬ "FC:FB:FB:01:FA:21", "4c:72:b9:56:fe:bc", "00-14-22-01-23-45"}
set table to {} repeat with burger in macList
set end of table to do shell script "curl " & apiRoot & "/" & burger delay 1.5
end repeat
set text item delimiters to linefeed return table as string </lang>
If this is part of a larger script you probably want to save and restore the text item delimiters:
<lang applescript>set savedTID to text item delimiters set text item delimiters to linefeed set tableText to table as string set text item delimiters to savedTID return tableText</lang>
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
Arturo
<lang rebol>loop ["FC-A1-3E" "FC:FB:FB:01:FA:21" "BC:5F:F4"] 'mac [
print [mac "=>" read ~"http://api.macvendors.com/%7Cmac%7C"] pause 1500
]</lang>
- Output:
FC-A1-3E => Samsung Electronics Co.,Ltd FC:FB:FB:01:FA:21 => Cisco Systems, Inc BC:5F:F4 => ASRock Incorporation
AutoHotkey
<lang AutoHotkey>macLookup(MAC){ WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1") WebRequest.Open("GET", "http://api.macvendors.com/" MAC) WebRequest.Send() return WebRequest.ResponseText }</lang> Examples:<lang AutoHotkey>MsgBox % macLookup("00-14-22-01-23-45")</lang>
Outputs:
Dell Inc.
BaCon
This code requires BaCon 3.8.2 or higher. <lang bacon>OPTION TLS TRUE
website$ = "api.macvendors.com" mac$ = "b0:52:16:d0:3c:fb"
OPEN website$ & ":443" FOR NETWORK AS mynet
SEND "GET /" & mac$ & " HTTP/1.1\r\nHost: " & website$ & "\r\n\r\n" TO mynet RECEIVE info$ FROM mynet
CLOSE NETWORK mynet
PRINT TOKEN$(info$, 2, "\r\n\r\n")</lang>
- Output:
Hon Hai Precision Ind. Co.,Ltd.
C
Takes MAC address as input, prints usage on incorrect invocation, requires libcurl <lang C>
- include <curl/curl.h>
- include <string.h>
- include <stdlib.h>
- include <stdio.h>
/* Length of http://api.macvendors.com/ */
- define FIXED_LENGTH 16
struct MemoryStruct {
char *memory; size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; mem->memory = realloc(mem->memory, mem->size + realsize + 1); memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize;
}
void checkResponse(char* str){ char ref[] = "Vendor not found"; int len = strlen(str),flag = 1,i;
if(len<16) fputs(str,stdout); else{ for(i=0;i<len && i<16;i++) flag = flag && (ref[i]==str[i]);
flag==1?fputs("N/A",stdout):fputs(str,stdout); } }
int main(int argC,char* argV[]) { if(argC!=2) printf("Usage : %s <MAC address>",argV[0]); else{ CURL *curl; int len = strlen(argV[1]); char* str = (char*)malloc((FIXED_LENGTH + len)*sizeof(char)); struct MemoryStruct chunk; CURLcode res;
chunk.memory = malloc(1); chunk.size = 0;
if ((curl = curl_easy_init()) != NULL) {
sprintf(str,"http://api.macvendors.com/%s",argV[1]);
curl_easy_setopt(curl, CURLOPT_URL, str);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
free(str);
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
checkResponse(chunk.memory);
return EXIT_SUCCESS; }
curl_easy_cleanup(curl);
} }
return EXIT_FAILURE;
} </lang> Invocation and output :
C:\rosettaCode>macLookUp 00-11-22-33-44-55-66 CIMSYS Inc C:\rosettaCode>macLookUp 10-11-22-33-44-55-66 N/A
C#
<lang csharp>using System; using System.Net; using System.Net.Http; using System.Threading.Tasks;
class Program {
static async Task<string> LookupMac(string MacAddress) { var uri = new Uri("http://api.macvendors.com/" + WebUtility.UrlEncode(MacAddress)); using (var wc = new HttpClient()) return await wc.GetStringAsync(uri); } static void Main(string[] args) { foreach (var mac in new string[] { "88:53:2E:67:07:BE", "FC:FB:FB:01:FA:21", "D4:F4:6F:C9:EF:8D" }) Console.WriteLine(mac + "\t" + LookupMac(mac).Result); Console.ReadLine(); }
}</lang>
- Output:
88:53:2E:67:07:BE Intel Corporate FC:FB:FB:01:FA:21 Cisco Systems, Inc D4:F4:6F:C9:EF:8D Apple, Inc.
C++
<lang cpp>// This code is based on the example 'Simple HTTP Client' included with // the Boost documentation.
- include <boost/beast/core.hpp>
- include <boost/beast/http.hpp>
- include <boost/beast/version.hpp>
- include <boost/asio/connect.hpp>
- include <boost/asio/ip/tcp.hpp>
- include <iostream>
- include <string>
bool get_mac_vendor(const std::string& mac, std::string& vendor) {
namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; using tcp = net::ip::tcp;
net::io_context ioc; tcp::resolver resolver(ioc); const char* host = "api.macvendors.com";
beast::tcp_stream stream(ioc); stream.connect(resolver.resolve(host, "http"));
http::request<http::string_body> req{http::verb::get, "/" + mac, 10}; req.set(http::field::host, host); req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); http::write(stream, req);
beast::flat_buffer buffer; http::response<http::string_body> res; http::read(stream, buffer, res);
bool success = res.result() == http::status::ok; if (success) vendor = res.body();
beast::error_code ec; stream.socket().shutdown(tcp::socket::shutdown_both, ec); if (ec && ec != beast::errc::not_connected) throw beast::system_error{ec};
return success;
}
int main(int argc, char** argv) {
if (argc != 2 || strlen(argv[1]) == 0) { std::cerr << "usage: " << argv[0] << " MAC-address\n"; return EXIT_FAILURE; } try { std::string vendor; if (get_mac_vendor(argv[1], vendor)) { std::cout << vendor << '\n'; return EXIT_SUCCESS; } else { std::cout << "N/A\n"; } } catch(std::exception const& e) { std::cerr << "Error: " << e.what() << std::endl; } return EXIT_FAILURE;
}</lang>
- Output:
% ./mac_vendor_lookup 0c:4d:e9:00:00:00 Apple, Inc.
Common Lisp
<lang Common Lisp>(quicklisp:quickload :Drakma) ; or load it in another way
(defun mac-vendor (mac)
(check-type mac string "A MAC address as a string") (multiple-value-bind (vendor status) (drakma:http-request (format nil "http://api.macvendors.com/~a" mac)) (if (= 200 status) (format t "~%Vendor is ~a" vendor) (error "~%Not a MAC address: ~a" mac))))
</lang>
Delphi
<lang Delphi> program MAC_Vendor_Lookup;
{$APPTYPE CONSOLE}
uses
System.SysUtils, IdHttp;
function macLookUp(mac: string): string; begin
Result := ; with TIdHTTP.Create(nil) do begin try Result := Get('http://api.macvendors.com/' + mac);
except on E: Exception do Writeln(e.Message); end; Free; end;
end;
begin
Writeln(macLookUp('FC-A1-3E')); sleep(1000); Writeln(macLookUp('FC:FB:FB:01:FA:21')); sleep(1000); Writeln(macLookUp('BC:5F:F4')); readln;
end.</lang>
- Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc ASRock Incorporation
Factor
<lang factor>USING: accessors calendar continuations http.client io kernel sequences threads ;
- mac-vendor ( str -- str )
"http://api.macvendors.com/" prepend [ http-get nip ] [ nip response>> message>> ] recover ;
"FC-A1-3E" "FC:FB:FB:01:FA:21" "10-11-22-33-44-55-66" [ mac-vendor print 1 seconds sleep ] tri@</lang>
- Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc Not Found
FreeBASIC
<lang freebasic>Function pipeout(Byval s As String = "") Byref As String
Var f = Freefile Dim As String tmp Open Pipe s For Input As #f s = "" Do Until Eof(f) Line Input #f, tmp s &= tmp Loop Close #f Return s
End Function
Function lookupvendor(webpage As String, mac As String) As String
Return pipeout("powershell " + "(Invoke-WebRequest " + webpage + mac + ")")
End Function
Dim As String macs(1 To 4) = {"FC-A1-3E","FC:FB:FB:01:FA:21","88:53:2E:67:07:BE","D4:F4:6F:C9:EF:8D"}
For i As Integer = 1 To Ubound(macs)
Var d = lookupvendor("api.macvendors.com/", macs(i)) Var e = Instr(d, "RawContent") Print Mid(d, 66, e-66)
Next i Sleep </lang>
- Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc Intel Corporate Apple, Inc.
Free Pascal
<lang pascal>program MACVendorLookup;
uses
fphttpclient;
var
res: String;
begin
if paramCount > 0 then begin
With TFPHttpClient.Create(Nil) do try allowRedirect := true; try res := Get('http://api.macvendors.com/' + ParamStr(1)); writeLn(res); except writeLn('N/A'); end; finally Free; end; end;
end.</lang>
- Output:
./MACVendorLookup 10-11-22-33-44-55-66 N/A ./MACVendorLookup 00-11-22-33-44-55-66 CIMSYS Inc
Go
<lang go>package main
import ( "net/http" "fmt" "io/ioutil" )
func macLookUp(mac string) (res string){ resp, _ := http.Get("http://api.macvendors.com/" + mac) body, _ := ioutil.ReadAll(resp.Body) res = string(body) return }
func main() { fmt.Println(macLookUp("FC-A1-3E")) fmt.Println(macLookUp("FC:FB:FB:01:FA:21")) fmt.Println(macLookUp("BC:5F:F4")) } </lang>
- Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc ASRock Incorporation
Haskell
<lang haskell>#!/usr/bin/env stack {- stack
script --resolver lts-9.0 --package bytestring --package http-client --package http-types
-}
{-# LANGUAGE MultiWayIf #-}
import Control.Exception (try) import Control.Monad (forM_) import qualified Data.ByteString.Lazy.Char8 as L8 (ByteString, unpack) import Network.HTTP.Client
(Manager, parseRequest, httpLbs, responseStatus, responseBody, newManager, defaultManagerSettings, Response, HttpException)
import Network.HTTP.Types.Status (statusIsSuccessful, notFound404) import System.Environment (getArgs) import Text.Printf (printf)
fetchURL :: Manager
-> String -> IO (Either HttpException (Response L8.ByteString))
fetchURL mgr url = try $ do
req <- parseRequest url httpLbs req mgr
lookupMac :: Manager -> String -> IO String lookupMac mgr mac = do
eth <- fetchURL mgr $ "http://api.macvendors.com/" ++ mac return $ case eth of Left _ -> "null" Right resp -> let body = responseBody resp status = responseStatus resp in if | status == notFound404 -> "N/A" | not (statusIsSuccessful status) -> "null" | otherwise -> L8.unpack body
main :: IO () main = do
args <- getArgs mgr <- newManager defaultManagerSettings forM_ args $ \mac -> do putStr $ printf "%-17s" mac ++ " = " vendor <- lookupMac mgr mac putStrLn vendor</lang>
- Output:
$ ./RosettaMac.hs 00:15:ed:f0:00:00 ff:ff:ff:ff:ff:ff 88:53:2E:67:07:BE FC:FB:FB:01:FA:21 D4:F4:6F:C9:EF:8D banana 00:15:ed:f0:00:00 = Fulcrum Microsystems, Inc. ff:ff:ff:ff:ff:ff = N/A 88:53:2E:67:07:BE = Intel Corporate FC:FB:FB:01:FA:21 = Cisco Systems, Inc D4:F4:6F:C9:EF:8D = Apple, Inc. banana = N/A
J
Solution <lang j>require 'web/gethttp' lookupMACvendor=: [: gethttp 'http://api.macvendors.com/'&,</lang> Example Usage <lang j> addr=: '88:53:2E:67:07:BE';'FC:FB:FB:01:FA:21';'D4:F4:6F:C9:EF:8D';'23:45:67'
(,&' ' , lookupMACvendor)&> addr
88:53:2E:67:07:BE Intel Corporate FC:FB:FB:01:FA:21 Cisco Systems, Inc D4:F4:6F:C9:EF:8D Apple, Inc. 23:45:67 Vendor not found</lang>
Java
<lang java>package com.jamesdonnell.MACVendor;
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL;
/** MAC Vendor Lookup class.
* www.JamesDonnell.com * @author James A. Donnell Jr. */
public class Lookup { /** Base URL for API. The API from www.macvendors.com was chosen. */ private static final String baseURL = "http://api.macvendors.com/";
/** Performs lookup on MAC address(es) supplied in arguments. * @param args MAC address(es) to lookup. */ public static void main(String[] args) { for (String arguments : args) System.out.println(arguments + ": " + get(arguments)); }
/** Performs lookup on supplied MAC address. * @param macAddress MAC address to lookup. * @return Manufacturer of MAC address. */ private static String get(String macAddress) { try { StringBuilder result = new StringBuilder(); URL url = new URL(baseURL + macAddress); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } rd.close(); return result.toString(); } catch (FileNotFoundException e) { // MAC not found return "N/A"; } catch (IOException e) { // Error during lookup, either network or API. return null; } } }</lang>
JavaScript
<lang javascript> var mac = "88:53:2E:67:07:BE"; function findmac(){ window.open("http://api.macvendors.com/" + mac); }
findmac(); </lang>
- Output:
Intel Corporate
Julia
<lang julia># v0.6.0
using Requests
function getvendor(addr::String)
try get("http://api.macvendors.com/$addr") |> readstring catch e nothing end
end
for addr in ["88:53:2E:67:07:BE", "FC:FB:FB:01:FA:21", "D4:F4:6F:C9:EF:8D", "23:45:67"]
println("$addr -> ", getvendor(addr))
end</lang>
- Output:
88:53:2E:67:07:BE -> Intel Corporate FC:FB:FB:01:FA:21 -> Cisco Systems, Inc D4:F4:6F:C9:EF:8D -> Apple, Inc. 23:45:67 -> Vendor not found
Kotlin
<lang scala>// version 1.1.2
import java.net.URL
fun lookupVendor(mac: String) = URL("http://api.macvendors.com/" + mac).readText()
fun main(args: Array<String>) {
val macs = arrayOf("FC-A1-3E", "FC:FB:FB:01:FA:21", "88:53:2E:67:07:BE", "D4:F4:6F:C9:EF:8D") for (mac in macs) println(lookupVendor(mac))
}</lang>
- Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc Intel Corporate Apple, Inc.
Logo
<lang logo>make "api_root "http://api.macvendors.com/ make "mac_list [88:53:2E:67:07:BE D4:F4:6F:C9:EF:8D FC:FB:FB:01:FA:21
4c:72:b9:56:fe:bc 00-14-22-01-23-45]
to lookup_vendor :mac
output first shell (sentence [curl -s] (word :api_root :mac) [&& echo])
end
foreach :mac_list [
print lookup_vendor ? wait 90
] bye</lang>
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
Lua
<lang lua>-- Requires LuaSocket extension by Lua -- Created by James A. Donnell Jr. -- www.JamesDonnell.com
local baseURL = "http://api.macvendors.com/"
local function lookup(macAddress) http = require "socket.http" result, statuscode, content = http.request(baseURL .. macAddress) return result end
local macAddress = "FC-A1-3E-2A-1C-33" print(lookup(macAddress))</lang>
M2000 Interpreter
<lang M2000 Interpreter> Module Checkit {
httpGet$=lambda$ (url$, timeout=500)->{ declare htmldoc "WinHttp.WinHttpRequest.5.1" Method htmldoc "SetTimeouts", timeout, timeout, timeout, timeout Method htmldoc "open","GET", url$, false Method htmldoc "setRequestHeader","Content-Type", "application/x-www-form-urlencoded" Method htmldoc "send" With htmldoc, "responseText" as ready$ res$=trim$(ready$) if left$(res$,1)="{" then ="N/A" else =res$ end if declare htmldoc nothing } Urls=("88:53:2E:67:07:BE", "FC:FB:FB:01:FA:21", "D4:F4:6F:C9:EF:8D", "23:45:67") url=each(URLs) While Url { Print Array$(URL), httpGet$("http://api.macvendors.com/"+Array$(URL)) Wait 20 }
} Checkit </lang>
Mathematica/Wolfram Language
<lang Mathematica>macLookup[mac_String] := Quiet[Check[Import["http://api.macvendors.com/" <> mac], "N/A"]]</lang> Examples:<lang Mathematica>macLookup["00-14-22-01-23-45"]</lang>
Outputs:
Dell Inc.
Nim
<lang Nim>import httpclient
for mac in ["FC-A1-3E", "FC:FB:FB:01:FA:21", "BC:5F:F4"]:
echo newHttpClient().getContent("http://api.macvendors.com/"&mac)</lang>
- Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc ASRock Incorporation
OCaml
<lang OCaml> (* build with ocamlfind ocamlopt -package netclient -linkpkg macaddr.ml -o macaddr *)
open Printf open Nethttp_client.Convenience open Unix
(* example vendors, including a nonsense one *)
let vendors = ["FF:FF:FF:67:07:BE"; "D4:F4:6F:C9:EF:8D"; "FC:FB:FB:01:FA:21"; "88:53:2E:67:07:BE"]
let get_vendor addr =
sleep 3; (* built-in delay to handle rate-limiting at macvendors.com *) let client = http_get_message ("http://api.macvendors.com/" ^ addr) in match client # response_status_code with | 200 -> client # response_body # value | 404 -> "N/A" | _ -> "NULL"
let rec parse_vendors vendors =
match vendors with | [] -> [] | hd::tl -> get_vendor hd :: parse_vendors tl
let rec print_vendors vendor_list =
match vendor_list with | [] -> "" | hd::tl -> printf "%s\n" hd; print_vendors tl
let main =
let vendor_list = parse_vendors vendors in print_vendors vendor_list
</lang>
- Output:
N/A Apple, Inc. Cisco Systems, Inc Intel Corporate
Perl
<lang perl>#!/usr/bin/env perl -T use v5.18.2; use warnings; use LWP; use Time::HiRes qw(sleep);
our $VERSION = 1.000_000;
my $ua = LWP::UserAgent->new;
no warnings 'qw'; my @macs = qw(
FC-A1-3EFC:FB:FB:01:FA:21 00,0d,4b Rhubarb 00-14-22-01-23-45 10:dd:b1 D4:F4:6F:C9:EF:8D FC-A1-3E 88:53:2E:67:07:BE 23:45:67 FC:FB:FB:01:FA:21 BC:5F:F4
);
while (my $mac = shift @macs) {
my $vendor = get_mac_vendor($mac); if ($vendor) { say "$mac = $vendor"; } sleep 1.5 if @macs;
}
sub get_mac_vendor {
my $s = shift;
my $req = HTTP::Request->new( GET => "http://api.macvendors.com/$s" ); my $res = $ua->request($req);
# A error related to the network connectivity or the API should # return a null result. if ( $res->is_error ) { return; }
# A MAC address that does not return a valid result should # return the String "N/A". if ( !$res->content or $res->content eq 'Vendor not found' ) { return 'N/A'; }
return $res->content;
}
- IEEE 802:
- Six groups of two hexadecimal digits separated by hyphens or colons,
- like 01-23-45-67-89-ab or 01:23:45:67:89:ab
- Three groups of four hexadecimal digits separated by dots (.),
- like 0123.4567.89ab
- sub validmac {
- my $s = shift;
- my $hex = qr{ [A-Fa-f[:digit:]] }xms;
- my $hex2ws = qr{ [-:] $hex{2} }xms;
- if ( $s =~ m{\A $hex{2} $hex2ws{5} \z}xms
- or $s =~ m{\A $hex{4} [.] $hex{4} [.] $hex{4} \z}xms )
- {
- return 'true';
- }
- return;
- }</lang>
- Output:
FC-A1-3EFC:FB:FB:01:FA:21 = Samsung Electronics Co.,Ltd 00,0d,4b = Roku, Inc. 00-14-22-01-23-45 = Dell Inc. 10:dd:b1 = Apple, Inc. D4:F4:6F:C9:EF:8D = Apple, Inc. FC-A1-3E = Samsung Electronics Co.,Ltd 88:53:2E:67:07:BE = Intel Corporate FC:FB:FB:01:FA:21 = Cisco Systems, Inc BC:5F:F4 = ASRock Incorporation
Phix
without js -- libcurl string test = "00-11-22-33-44-55-66" -- CIMSYS Inc --string test = "10-11-22-33-44-55-66" -- N/A include builtins/libcurl.e curl_global_init() atom curl = curl_easy_init() string url = sprintf("http://api.macvendors.com/%s",{test}) curl_easy_setopt(curl, CURLOPT_URL, url) object res = curl_easy_perform_ex(curl) if string(res) then if res="Vendor not found" or res=`{"errors":{"detail":"Not Found"}}` then res = "N/A" end if ?res else ?{"error",res} end if curl_easy_cleanup(curl) curl_global_cleanup()
- Output:
CIMSYS Inc
PHP
<lang php><?php $apiRoot = "https://api.macvendors.com"; $macList = array("88:53:2E:67:07:BE", "D4:F4:6F:C9:EF:8D", "FC:FB:FB:01:FA:21", "4c:72:b9:56:fe:bc", "00-14-22-01-23-45");
$curl = curl_init(); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); foreach ($macList as $burger) {
curl_setopt($curl, CURLOPT_URL, "$apiRoot/$burger"); echo(curl_exec($curl)); echo("\n"); sleep(2);
} curl_close($curl); ?></lang>
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
PowerShell
<lang powershell>$apiRoot = "http://api.macvendors.com" $macAddresses = @("88:53:2E:67:07:BE", "D4:F4:6F:C9:EF:8D",
"FC:FB:FB:01:FA:21", "4c:72:b9:56:fe:bc", "00-14-22-01-23-45")
$macAddresses | % {
(Invoke-WebRequest "$apiRoot/$_").Content Start-Sleep 1.5
}</lang>
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
Python
<lang python>import requests
for addr in ['88:53:2E:67:07:BE', 'FC:FB:FB:01:FA:21',
'D4:F4:6F:C9:EF:8D', '23:45:67']: vendor = requests.get('http://api.macvendors.com/' + addr).text print(addr, vendor)</lang>
- Output:
88:53:2E:67:07:BE Intel Corporate FC:FB:FB:01:FA:21 Cisco Systems, Inc D4:F4:6F:C9:EF:8D Apple, Inc. 23:45:67 Vendor not found
Racket
<lang racket>#lang racket
(require net/url)
(define (lookup-MAC-address addr)
(port->string (get-pure-port (url "http" #f "api.macvendors.com" #f #t (list (path/param addr null)) null #f))))
(module+ test (for ((i (in-list '("88:53:2E:67:07:BE"
"FC:FB:FB:01:FA:21" "D4:F4:6F:C9:EF:8D")))) (printf "~a\t~a~%" i (lookup-MAC-address i))))</lang>
- Output:
88:53:2E:67:07:BE Intel Corporate FC:FB:FB:01:FA:21 Cisco Systems, Inc D4:F4:6F:C9:EF:8D Apple, Inc.
Raku
(formerly Perl 6)
Apparently there is some rate limiting on place now, sleep a bit between requests.
<lang perl6>use HTTP::UserAgent;
my $ua = HTTP::UserAgent.new;
$ua.timeout = 10; # seconds
my $server = 'http://api.macvendors.com/';
sub lookup ($mac) {
my $response = $ua.get: "$server+$mac"; sleep 1; return $response.is-success ?? $response.content !! 'N/A'; CATCH { # Normally you would report some information about what default { Nil } # went wrong, but the task specifies to ignore errors. }
}
for < BC:5F:F4 FC-A1-3E 10:dd:b1 00:0d:4b 23:45:67 > -> $mac { say lookup $mac }</lang>
- Output:
ASRock Incorporation Samsung Electronics Co.,Ltd Apple, Inc. Roku, Inc. N/A
Red
<lang Red>print read rejoin ask "MAC address: " </lang>
- Output:
MAC address: 88:53:2E:67:07:BE Intel Corporate
REXX
This REXX version only works under Microsoft Windows and Regina REXX. <lang rexx>/*REXX pgm shows a network device's manufacturer based on the Media Access Control addr.*/ win_command = 'getmac' /*name of the Microsoft Windows command*/ win_command_options = '/v /fo list' /*options of " " " */ ?3= 'Network Adapter:' /*search keywords for Network Adapter. */ ?4= 'Physical Address:' /* " " " Physical Address.*/ upper ?3 ?4 /*uppercase in case for capitol letters*/ @.=; @.0= 0 /*just─in─case values for the keywords.*/ rc= 0 /* " " " value for the returnCode*/ address system win_command win_command_options with output stem @. /*issue command.*/ if rc\==0 then do /*display an error if not successful. */
say say '***error*** from command: ' win_command win_command_options say 'Return code was: ' rc say exit rc end
MACaddr=. /*just─in─case value for the keyword. */ maker=. /* " " " " " " " */
do j=1 for @.0; $= @.j; upper $ /*parse each of the possible responses.*/ if left($, length(?3))=?3 then maker= subword(@.j, 3) /*is this the one?*/ if left($, length(?4))=?4 then MACaddr= word(@.j, 3) /* " " " " */ end /*k*/ /* [↑] Now, display good or bad stuff.*/
if maker=. | MACaddr==. then say 'MAC address manufacturer not found.'
else say 'manufacturer for MAC address ' MACaddr " is " maker
exit 0 /*stick a fork in it, we're all done. */</lang>
- output when using the default input:
manufacturer for MAC address 00-16-17-F9-C8-AA is Broadcom NetLink (TM) Gigabit Ethernet
Ring
<lang ring>
- Project: MAC Vendor Lookup
load "stdlib.ring" macs = ["FC-A1-3E","FC:FB:FB:01:FA:21","88:53:2E:67:07:BE","D4:F4:6F:C9:EF:8D"] for mac = 1 to len(macs)
lookupvendor(macs[mac])
next
func lookupvendor(mac)
url = download("api.macvendors.com/" + mac) see url + nl
</lang> Output:
Samsung Electronics Co.,Ltd Cisco Systems, Inc Intel Corporate Apple, Inc.
Ruby
<lang ruby>require 'net/http'
arr = ['88:53:2E:67:07:BE', 'FC:FB:FB:01:FA:21', 'D4:F4:6F:C9:EF:8D', '23:45:67']
arr.each do |addr|
vendor = Net::HTTP.get('api.macvendors.com', "/#{addr}/") rescue nil puts "#{addr} #{vendor}"
end</lang>
- Output:
88:53:2E:67:07:BE Intel Corporate FC:FB:FB:01:FA:21 Cisco Systems, Inc D4:F4:6F:C9:EF:8D Apple, Inc. 23:45:67 Vendor not found
Rust
<lang rust>extern crate reqwest;
use std::{thread, time};
fn get_vendor(mac: &str) -> Option<String> {
let mut url = String::from("http://api.macvendors.com/"); url.push_str(mac); let url_ref = &url; match reqwest::get(url_ref) { Ok(mut res) => match res.text() { Ok(text) => { if text.contains("Not Found") { Some("N/A".to_string()) } else { Some(text) } } Err(e) => { println!("{:?}", e); None } }, Err(e) => { println!("{:?}", e); None } }
}
fn main() {
let duration = time::Duration::from_millis(1000); match get_vendor("88:53:2E:67:07:BE") { None => println!("Error!"), Some(text) => println!("{}", text), } thread::sleep(duration); match get_vendor("FC:FB:FB:01:FA:21") { None => println!("Error!"), Some(text) => println!("{}", text), } thread::sleep(duration); match get_vendor("FC-A1-3E") { None => println!("Error!"), Some(text) => println!("{}", text), } thread::sleep(duration); match get_vendor("abcdefg") { None => println!("Error!"), Some(text) => println!("{}", text), }
} </lang> Output:
Intel Corporate Cisco Systems, Inc Samsung Electronics Co.,Ltd N/A
Scala
<lang scala>object LookUp extends App {
val macs = Seq("FC-A1-3E", "FC:FB:FB:01:FA:21", "88:53:2E:67:07:BE", "D4:F4:6F:C9:EF:8D")
def lookupVendor(mac: String) = scala.io.Source.fromURL("""http://api.macvendors.com/""" + mac, "UTF-8").mkString
macs.foreach(mac => println(lookupVendor(mac)))
}</lang>
Scheme
<lang scheme>(import http-client (chicken io)) (define api-root "http://api.macvendors.com") (define mac-addresses '("88:53:2E:67:07:BE" "D4:F4:6F:C9:EF:8D"
"FC:FB:FB:01:FA:21" "4c:72:b9:56:fe:bc" "00-14-22-01-23-45"))
(define get-vendor (lambda (mac-address)
(with-input-from-request (string-append api-root "/" mac-address) #f read-string)))
(map (lambda (burger) (display (get-vendor burger)) (newline) (sleep 2))
mac-addresses)</lang>
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
Tcl
<lang Tcl>package require http
- finally is a bit like go's defer
proc finally args {
tailcall trace add variable :#finally#: unset [list apply [list args $args]]
}
- basic wrapper for http::geturl
proc geturl {url} {
set tok [::http::geturl $url] finally ::http::cleanup $tok ::http::data $tok
} proc maclookup {mac} {
geturl http://api.macvendors.com/$mac
}
foreach mac {00-14-22-01-23-45 88:53:2E:67:07:BE} {
puts "$mac\t[maclookup $mac]"
}</lang>
- Output:
00-14-22-01-23-45 Dell Inc. 88:53:2E:67:07:BE Intel Corporate
UNIX Shell
Surprising that nobody had implemented the Bash / Shell version yet. <lang bash>macList=(88:53:2E:67:07:BE D4:F4:6F:C9:EF:8D FC:FB:FB:01:FA:21
4c:72:b9:56:fe:bc 00-14-22-01-23-45)
for burger in "${macList[@]}"; do
curl -s "http://api.macvendors.com/$burger" && echo sleep 2
done</lang>
It can be made to work in a pure-POSIX shell without array variables:
<lang bash>set -- 88:53:2E:67:07:BE D4:F4:6F:C9:EF:8D FC:FB:FB:01:FA:21 \
4c:72:b9:56:fe:bc 00-14-22-01-23-45
for burger; do
curl -s "http://api.macvendors.com/$burger" && echo sleep 2
done</lang>
The output is the same either way:
- Output:
Intel Corporate Apple, Inc. Cisco Systems, Inc PEGATRON CORPORATION Dell Inc.
VBScript
<lang> a=array("00-20-6b-ba-d0-cb","00-40-ae-04-87-86") set WebRequest = CreateObject("WinHttp.WinHttpRequest.5.1")
for each MAC in a
if b<>0 then wscript.echo "Spacing next request...": wscript.sleep 2000 WebRequest.Open "GET", "http://api.macvendors.com/"& mac,1 WebRequest.Send() WebRequest.WaitForResponse b=b+1 wscript.echo mac & " -> " & WebRequest.ResponseText
next </lang> Output:
00-20-6b-ba-d0-cb -> KONICA MINOLTA HOLDINGS, INC. Spacing next request... 00-40-ae-04-87-86 -> DELTA CONTROLS, INC.
Wren
Wren CLI doesn't currently expose a way to look up a MAC address.
However, if Wren is embedded in (say) a suitable Go program, then we can ask the latter to do it for us. <lang ecmascript>/* mac_vendor_lookup.wren */ class MAC {
foreign static lookup(address)
}
System.print(MAC.lookup("FC:FB:FB:01:FA:21")) for (i in 1..1e8) {} // slow down request System.print(MAC.lookup("23:45:67"))</lang>
which we embed in the following Go program and run it.
<lang go>/* mac_vendor_lookup.go */ package main
import (
wren "github.com/crazyinfin8/WrenGo" "io/ioutil" "net/http"
)
type any = interface{}
func macLookup(vm *wren.VM, parameters []any) (any, error) {
mac := parameters[1].(string) resp, err := http.Get("http://api.macvendors.com/" + mac) if err != nil { return nil, nil } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, nil } var vendor = string(body) if vendor == `{"errors":{"detail":"Not Found"}}` { return "N/A", nil } return vendor, nil
}
func main() {
vm := wren.NewVM() fileName := "mac_vendor_lookup.wren" methodMap := wren.MethodMap{"static lookup(_)": macLookup} classMap := wren.ClassMap{"MAC": wren.NewClass(nil, nil, methodMap)} module := wren.NewModule(classMap) vm.SetModule(fileName, module) vm.InterpretFile(fileName) vm.Free()
}</lang>
- Output:
Cisco Systems, Inc N/A
zkl
Uses libcurl (the multiprotocol file transfer library) to do the web query <lang zkl>var [const] CURL=Import("zklCurl"); // libcurl const MAC_VENDORS="http://api.macvendors.com/";
fcn lookUp(macAddress){
httpAddr:=MAC_VENDORS + macAddress; vender:=CURL().get(httpAddr); //-->(Data,bytes of header,bytes of trailer) vender=vender[0].del(0,vender[1]); // remove HTTP header vender.text; // Data --> String (Data is a byte bucket)
}</lang> <lang zkl>lookUp("FC-A1-3E-2A-1C-33").println(); lookUp("4c:72:b9:56:fe:bc").println(); lookUp("foobar").println();</lang>
- Output:
Samsung Electronics Co.,Ltd PEGATRON CORPORATION Vendor not found
Zoea
<lang Zoea> program: mac_vendor_lookup
data: 'http://api.macvendors.com/'
input: 'D4:F4:6F:C9:EF:8D' derive: 'http://api.macvendors.com/D4:F4:6F:C9:EF:8D' output: 'Apple, Inc.' </lang>
Zoea Visual
- Programming Tasks
- Solutions by Programming Task
- Network Tools
- Ada
- AWS
- APL
- HttpCommand
- AppleScript
- Arturo
- AutoHotkey
- BaCon
- C
- C sharp
- C++
- Boost
- Common Lisp
- Delphi
- System.SysUtils
- IdHttp
- Factor
- FreeBASIC
- Free Pascal
- Go
- Haskell
- Http-client
- J
- Java
- JavaScript
- Julia
- Kotlin
- Logo
- Lua
- M2000 Interpreter
- Mathematica
- Wolfram Language
- Nim
- OCaml
- Perl
- Phix
- Phix/libcurl
- PHP
- PowerShell
- Python
- Requests
- Racket
- Raku
- Red
- REXX
- Ring
- Ruby
- Rust
- Scala
- Scheme
- Tcl
- UNIX Shell
- VBScript
- Wren
- WrenGo
- Zkl
- Zoea
- Zoea Visual