MAC vendor lookup

From Rosetta Code
Revision as of 00:01, 18 October 2017 by Aamrun (talk | contribs) (Added C implementation.)
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.

Basic Task

The task is to 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". A error related to the network connectivity or the API should return a null result.

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.

C

Takes MAC address as input, prints usage on incorrect invocation, requires libcurl <lang C> /*Abhishek Ghosh, 18th October 2017*/

  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.

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>

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.

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>

Mathematica

<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

Perl

<lang perl>#!/usr/bin/env perl -T use 5.018_002; use warnings; use LWP;

our $VERSION = 1.000_000;

my $ua = LWP::UserAgent->new;

my @macs = (

   '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',

);

for my $mac (@macs) {

   my $vendor = get_mac_vendor($mac);
   if ($vendor) {
       say "$mac = $vendor";
   }

}

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

Perl 6

Works with: Rakudo version 2016.12

<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";
   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

PicoLisp

<lang PicoLisp>(load "@lib/http.l")

(de maclookup (M)

  (client "api.macvendors.com" 80
     M
     (while (line))
     (line T) ) )

(test

  "Intel Corporate"
  (maclookup "88:53:2E:67:07:BE") )

(test

  "Apple, Inc."
  (maclookup "D4:F4:6F:C9:EF:8D") )</lang>

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.

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

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

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