MAC vendor lookup

From Rosetta Code
Revision as of 16:16, 31 July 2022 by Markjreed (talk | contribs) (→‎{{header|APL}}: formatting.)
Task
MAC vendor lookup
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

Library: AWS

<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

Works with: Dyalog APL
Library: HttpCommand

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>

  1. include <curl/curl.h>
  2. include <string.h>
  3. include <stdlib.h>
  4. include <stdio.h>

/* Length of http://api.macvendors.com/ */

  1. 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++

Library: Boost

<lang cpp>// This code is based on the example 'Simple HTTP Client' included with // the Boost documentation.

  1. include <boost/beast/core.hpp>
  2. include <boost/beast/http.hpp>
  3. include <boost/beast/version.hpp>
  4. include <boost/asio/connect.hpp>
  5. include <boost/asio/ip/tcp.hpp>
  6. include <iostream>
  7. 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

Library: IdHttp

<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

Works with: GHC version 8.0.2
Library: http-client

<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.

Works with: UCB 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;

}

  1. IEEE 802:
  2. Six groups of two hexadecimal digits separated by hyphens or colons,
  3. like 01-23-45-67-89-ab or 01:23:45:67:89:ab
  4. Three groups of four hexadecimal digits separated by dots (.),
  5. like 0123.4567.89ab
  6. sub validmac {
  7. my $s = shift;
  8. my $hex = qr{ [A-Fa-f[:digit:]] }xms;
  9. my $hex2ws = qr{ [-:] $hex{2} }xms;
  10. if ( $s =~ m{\A $hex{2} $hex2ws{5} \z}xms
  11. or $s =~ m{\A $hex{4} [.] $hex{4} [.] $hex{4} \z}xms )
  12. {
  13. return 'true';
  14. }
  15. return;
  16. }</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

Library: Phix/libcurl
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

Translation of: AppleScript

<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

Translation of: AppleScript

<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

Library: requests

<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)

Works with: Rakudo version 2018.03

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>

  1. 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

Translation of: Applescript
Works with: Chicken Scheme
Library: http-client

<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

  1. finally is a bit like go's defer

proc finally args {

   tailcall trace add variable :#finally#: unset [list apply [list args $args]]

}

  1. 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

Translation of: AppleScript
Works with: Bourne Again SHell
Works with: Korn Shell version 93+
Works with: Z 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:

Works with: Bourne Shell
Works with: Almquist Shell

<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.

Library: WrenGo

<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

Translation of: Lua

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

MAC Vendor Lookup