2013-07-04 20:56:19 +00:00
/*
* ZeroTier One - Global Peer to Peer Ethernet
2014-02-16 20:40:22 +00:00
* Copyright ( C ) 2011 - 2014 ZeroTier Networks LLC
2013-07-04 20:56:19 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* - -
*
* ZeroTier may be used and distributed under the terms of the GPLv3 , which
* are available at : http : //www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form , please contact ZeroTier Networks
* LLC . Start here : http : //www.zerotier.com/
*/
2013-12-07 00:49:20 +00:00
# ifndef ZT_MAC_HPP
# define ZT_MAC_HPP
2013-07-04 20:56:19 +00:00
# include <stdio.h>
# include <stdlib.h>
2014-05-23 21:32:31 +00:00
# include <stdint.h>
2013-08-30 21:05:43 +00:00
2013-07-04 20:56:19 +00:00
# include "Constants.hpp"
# include "Utils.hpp"
2014-05-23 21:32:31 +00:00
# include "Address.hpp"
# include "Buffer.hpp"
2013-07-04 20:56:19 +00:00
namespace ZeroTier {
/**
2014-05-23 21:32:31 +00:00
* 48 - byte Ethernet MAC address
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
class MAC
2013-07-04 20:56:19 +00:00
{
public :
2014-05-23 21:32:31 +00:00
MAC ( ) throw ( ) : _m ( 0ULL ) { }
MAC ( const MAC & m ) throw ( ) : _m ( m . _m ) { }
/**
* @ param octet Single octet to fill entire MAC with ( e . g . 0xff for broadcast )
*/
MAC ( const unsigned char octet ) throw ( ) :
_m ( ( ( ( ( uint64_t ) octet ) & 0xffULL ) < < 40 ) |
( ( ( ( uint64_t ) octet ) & 0xffULL ) < < 32 ) |
( ( ( ( uint64_t ) octet ) & 0xffULL ) < < 24 ) |
( ( ( ( uint64_t ) octet ) & 0xffULL ) < < 16 ) |
( ( ( ( uint64_t ) octet ) & 0xffULL ) < < 8 ) |
( ( ( uint64_t ) octet ) & 0xffULL ) ) { }
MAC ( const unsigned char a , const unsigned char b , const unsigned char c , const unsigned char d , const unsigned char e , const unsigned char f ) throw ( ) :
_m ( ( ( ( ( uint64_t ) a ) & 0xffULL ) < < 40 ) |
( ( ( ( uint64_t ) b ) & 0xffULL ) < < 32 ) |
( ( ( ( uint64_t ) c ) & 0xffULL ) < < 24 ) |
( ( ( ( uint64_t ) d ) & 0xffULL ) < < 16 ) |
( ( ( ( uint64_t ) e ) & 0xffULL ) < < 8 ) |
( ( ( uint64_t ) f ) & 0xffULL ) ) { }
MAC ( const void * bits , unsigned int len ) throw ( ) { setTo ( bits , len ) ; }
MAC ( const Address & ztaddr , uint64_t nwid ) throw ( ) { fromAddress ( ztaddr , nwid ) ; }
/**
* Set MAC to zero
*/
inline void zero ( ) { _m = 0ULL ; }
/**
* @ return True if MAC is non - zero
*/
inline operator bool ( ) const throw ( ) { return ( _m ! = 0ULL ) ; }
2013-07-04 20:56:19 +00:00
/**
2014-05-23 21:32:31 +00:00
* @ param bits Raw MAC in big - endian byte order
* @ param len Length , must be > = 6 or result is zero
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline void setTo ( const void * bits , unsigned int len )
2013-07-04 20:56:19 +00:00
throw ( )
{
2014-05-23 21:32:31 +00:00
if ( len < 6 ) {
_m = 0ULL ;
return ;
}
const unsigned char * b = ( const unsigned char * ) bits ;
_m = ( ( ( ( uint64_t ) * b ) & 0xff ) < < 40 ) ; + + b ;
_m | = ( ( ( ( uint64_t ) * b ) & 0xff ) < < 32 ) ; + + b ;
_m | = ( ( ( ( uint64_t ) * b ) & 0xff ) < < 24 ) ; + + b ;
_m | = ( ( ( ( uint64_t ) * b ) & 0xff ) < < 16 ) ; + + b ;
_m | = ( ( ( ( uint64_t ) * b ) & 0xff ) < < 8 ) ; + + b ;
_m | = ( ( ( uint64_t ) * b ) & 0xff ) ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* @ param buf Destination buffer for MAC in big - endian byte order
* @ param len Length of buffer , must be > = 6 or nothing is copied
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline void copyTo ( void * buf , unsigned int len ) const
2013-07-04 20:56:19 +00:00
throw ( )
{
2014-05-23 21:32:31 +00:00
if ( len < 6 )
return ;
unsigned char * b = ( unsigned char * ) buf ;
* ( b + + ) = ( unsigned char ) ( ( _m > > 40 ) & 0xff ) ;
* ( b + + ) = ( unsigned char ) ( ( _m > > 32 ) & 0xff ) ;
* ( b + + ) = ( unsigned char ) ( ( _m > > 24 ) & 0xff ) ;
* ( b + + ) = ( unsigned char ) ( ( _m > > 16 ) & 0xff ) ;
* ( b + + ) = ( unsigned char ) ( ( _m > > 8 ) & 0xff ) ;
* b = ( unsigned char ) ( _m & 0xff ) ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* Append to a buffer in big - endian byte order
2013-07-04 20:56:19 +00:00
*
2014-05-23 21:32:31 +00:00
* @ param b Buffer to append to
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
template < unsigned int C >
inline void appendTo ( Buffer < C > & b ) const
throw ( std : : out_of_range )
2013-07-04 20:56:19 +00:00
{
2014-05-23 21:32:31 +00:00
unsigned char * p = ( unsigned char * ) b . appendField ( 6 ) ;
* ( p + + ) = ( unsigned char ) ( ( _m > > 40 ) & 0xff ) ;
* ( p + + ) = ( unsigned char ) ( ( _m > > 32 ) & 0xff ) ;
* ( p + + ) = ( unsigned char ) ( ( _m > > 24 ) & 0xff ) ;
* ( p + + ) = ( unsigned char ) ( ( _m > > 16 ) & 0xff ) ;
* ( p + + ) = ( unsigned char ) ( ( _m > > 8 ) & 0xff ) ;
* p = ( unsigned char ) ( _m & 0xff ) ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* @ return True if this is broadcast ( all 0xff )
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline bool isBroadcast ( ) const throw ( ) { return ( _m = = 0xffffffffffffULL ) ; }
/**
* @ return True if this is a multicast MAC
*/
inline bool isMulticast ( ) const throw ( ) { return ( ( _m & 0x010000000000ULL ) ! = 0ULL ) ; }
/**
* @ param True if this is a locally - administered MAC
*/
inline bool isLocallyAdministered ( ) const throw ( ) { return ( ( _m & 0x020000000000ULL ) ! = 0ULL ) ; }
/**
* @ param s Hex MAC , with or without : delimiters
*/
inline void fromString ( const char * s )
2013-07-04 20:56:19 +00:00
{
2014-05-23 21:32:31 +00:00
char tmp [ 8 ] ;
Utils : : unhex ( s , tmp , 6 ) ;
setTo ( tmp , 6 ) ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* @ return MAC address in standard : - delimited hex format
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline std : : string toString ( ) const
2013-07-04 20:56:19 +00:00
{
2014-05-23 21:32:31 +00:00
char tmp [ 24 ] ;
std : : string s ;
Utils : : snprintf ( tmp , sizeof ( tmp ) , " %.12llx " , _m ) ;
for ( int i = 0 ; i < 12 ; + + i ) {
if ( ( i > 0 ) & & ( ( i % 2 ) = = 0 ) )
s . push_back ( ' : ' ) ;
s . push_back ( tmp [ i ] ) ;
2013-07-04 20:56:19 +00:00
}
2014-05-23 21:32:31 +00:00
return s ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* Set this MAC to a MAC derived from an address and a network ID
*
* @ param ztaddr ZeroTier address
* @ param nwid 64 - bit network ID
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline void fromAddress ( const Address & ztaddr , uint64_t nwid )
2013-07-04 20:56:19 +00:00
throw ( )
{
2014-05-23 21:32:31 +00:00
uint64_t m = ( ( uint64_t ) firstOctetForNetwork ( nwid ) ) < < 40 ;
2014-05-23 23:21:57 +00:00
m | = ztaddr . toInt ( ) ; // a is 40 bits
2014-05-23 21:32:31 +00:00
m ^ = ( ( nwid > > 8 ) & 0xff ) < < 32 ;
m ^ = ( ( nwid > > 16 ) & 0xff ) < < 24 ;
m ^ = ( ( nwid > > 24 ) & 0xff ) < < 16 ;
m ^ = ( ( nwid > > 32 ) & 0xff ) < < 8 ;
m ^ = ( nwid > > 40 ) & 0xff ;
_m = m ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* Get the ZeroTier address for this MAC on this network ( assuming no bridging of course , basic unicast )
*
* This just XORs the next - lest - significant 5 bytes of the network ID again to unmask .
*
* @ param nwid Network ID
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline Address toAddress ( uint64_t nwid ) const
2013-07-04 20:56:19 +00:00
throw ( )
{
2014-05-23 23:21:57 +00:00
uint64_t a = _m & 0xffffffffffULL ; // least significant 40 bits of MAC are formed from address
a ^ = ( ( nwid > > 8 ) & 0xff ) < < 32 ; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it
2014-05-23 21:32:31 +00:00
a ^ = ( ( nwid > > 16 ) & 0xff ) < < 24 ;
a ^ = ( ( nwid > > 24 ) & 0xff ) < < 16 ;
a ^ = ( ( nwid > > 32 ) & 0xff ) < < 8 ;
a ^ = ( nwid > > 40 ) & 0xff ;
return Address ( a ) ;
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* @ param nwid Network ID
* @ return First octet of MAC for this network
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
static inline unsigned char firstOctetForNetwork ( uint64_t nwid )
2013-07-04 20:56:19 +00:00
throw ( )
{
2014-05-23 21:32:31 +00:00
unsigned char a = ( ( unsigned char ) ( nwid & 0xfe ) | 0x02 ) ; // locally administered, not multicast, from LSB of network ID
2014-06-18 15:25:30 +00:00
return ( ( a = = 0x52 ) ? 0x32 : a ) ; // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux
2013-07-04 20:56:19 +00:00
}
/**
2014-05-23 21:32:31 +00:00
* @ param i Value from 0 to 5 ( inclusive )
* @ return Byte at said position ( address interpreted in big - endian order )
2013-07-04 20:56:19 +00:00
*/
2014-05-23 21:32:31 +00:00
inline unsigned char operator [ ] ( unsigned int i ) const throw ( ) { return ( unsigned char ) ( ( _m > > ( 40 - ( i * 8 ) ) ) & 0xff ) ; }
2013-07-04 20:56:19 +00:00
2013-10-18 20:27:07 +00:00
/**
2014-05-23 21:32:31 +00:00
* @ return 6 , which is the number of bytes in a MAC , for container compliance
2013-10-18 20:27:07 +00:00
*/
2014-05-23 21:32:31 +00:00
inline unsigned int size ( ) const throw ( ) { return 6 ; }
inline MAC & operator = ( const MAC & m )
throw ( )
2013-07-04 20:56:19 +00:00
{
2014-05-23 21:32:31 +00:00
_m = m . _m ;
return * this ;
2013-07-04 20:56:19 +00:00
}
2014-05-23 21:32:31 +00:00
inline bool operator = = ( const MAC & m ) const throw ( ) { return ( _m = = m . _m ) ; }
inline bool operator ! = ( const MAC & m ) const throw ( ) { return ( _m ! = m . _m ) ; }
inline bool operator < ( const MAC & m ) const throw ( ) { return ( _m < m . _m ) ; }
inline bool operator < = ( const MAC & m ) const throw ( ) { return ( _m < = m . _m ) ; }
inline bool operator > ( const MAC & m ) const throw ( ) { return ( _m > m . _m ) ; }
inline bool operator > = ( const MAC & m ) const throw ( ) { return ( _m > = m . _m ) ; }
private :
uint64_t _m ;
2013-07-04 20:56:19 +00:00
} ;
} // namespace ZeroTier
# endif