ioctl programming under kernel 2.6 series by: Ev1lut10n a.k.a Bocah Tua Nakal ~ Int Security Release ~ Gopher: gopher://sdf.org/1/users/ev1lut10 content : - device controlling - ioctl on socket this article will show basics of ioctl usages .ioctl is a syscall commonly used for controlling devices under nix system. This ioctl function can be in user space or kernel space. on User Space this ioctl function is useful to perform some operations which can't be performed by other regular syscalls. ioctl function used to control any devices i/o .. IOCTL = Device Input and the Output Controller. for more complete explanations just take a look : man ioctl. have a good visit into my linux b0x: ============ ev1lut10n@ev1l:~$ cat /usr/include/sys/ioctl.h | grep 'int ioctl' extern int ioctl (int __fd, unsigned long int __request, ...) __THROW; ============ - considering above code the first parameter will be file descriptor number. - and the second will be our device dependent request code, say it : command ! - and for next argument as we may be untyped pointer in memory since there are so many benefits of ioctl we will limit here only in 3 parts: [Sample IOCTL Code in C] 1. Device Controlling ok make sure u include our beloved header at /usr/include/sys/ioctl.h: =================== #ifdef HAVE_SYS_IOCTL #include <sys/ioctl.h> #endif =================== #ifdef HAVE_SYS_IOCTL, where the ifdef directive is used to check whether we have ioctl or not. there are some functions related to this ioctl() such as: - open() when u use this funct don't forget it needs fcntl.h ====================================== root@mywisdom-Vostro1310:/usr/include# cat fcntl.h | grep 'open (' extern int open (__const char *__file, int __oflag, ...) __nonnull ((1) ======================================= this function mostly used to open a file descriptor before we use ioctl syscall here is a simple example, ex you wanna open /dev/cdrom: if(fd=open("/dev/cdrom",O_RDONLY)) so what's )_RDONLY. check out this flags desc below: ============================ O_RDONLY Only read operations permitted O_WRONLY Only write operations permitted O_RDWR Read and Write operations both permitted O_NONBLOCK Non-blocking, applies to open operation only O_APPEND All writes go to end of file O_CREAT Create file if it doesn't already exist O_TRUNC Delete existing contents of file O_EXCL Open fails if file already exists O_SHLOCK Get a "shared lock" on the file O_EXLOCK Get an "exclusive lock" on the file O_DIRECT Try to avoid all caching of operations O_FSYNC All writes immediately effective, no buffering O_NOFOLLOW If file is symbolic link, open it, don't follow it and the next parameter is optional where it's usually indicated the permissions - close() this will be used to close our FD that we've opened using open() func Here's sample for stopping and ejecting the cdrom device: ==================== /**some cdrom operation using ioctl by ev1lut10n**/ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <linux/cdrom.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #ifdef HAVE_SYS_IOCTL #include <sys/ioctl.h> #endif char menu(); int main () { int pilihan; int fd; fd=open ("/dev/cdrom", O_RDONLY); pilihan=menu(); if(pilihan==97) { fprintf(stdout,"\nStopping cdrom device.using ioctl syscall..\n"); ioctl (fd, CDROMSTOP,0); } else { fprintf(stdout,"\nEjecting cdrom device.using ioctl syscall..\n"); ioctl (fd, CDROMEJECT,0); } close (fd); return 0; } char menu() { char select_me; fprintf(stdout,"\nby: ev1lut10n"); fprintf(stdout,"\nWatcha gonna do ?? (type a or b)\n"); fprintf(stdout,"\na ---- stopping currently playing cd"); fprintf(stdout,"\nb ---- eject cdrom "); fprintf(stdout,"\ntype a or b :"); select_me=getchar(); return select_me; } ==================== AS u may see above we use 2 command for controlling cdrom device: ioctl (fd, CDROMSTOP,0); where here we use ioctl syscall to stop our cdrom device and ioctl (fd, CDROMEJECT,0); where we use ioctl syscall to eject our cdrom device before our ioctl we already have an open file descriptor : ============================ fd=open ("/dev/cdrom", O_RDONLY); ============================ where we've opened /dev/cdrom using O_RDONLY flag for more complete linux cdrom ioctl programming you may see any command related to this device at: ======= root@ev1l:/home/mywisdom/c/ioctl# cat /usr/include/linux/cdrom.h | grep "#define CDROM" #define CDROMPAUSE 0x5301 /* Pause Audio Operation */ #define CDROMRESUME 0x5302 /* Resume paused Audio Operation */ #define CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */ #define CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index #define CDROMREADTOCHDR 0x5305 /* Read TOC header #define CDROMREADTOCENTRY 0x5306 /* Read TOC entry #define CDROMSTOP 0x5307 /* Stop the cdrom drive */ #define CDROMSTART 0x5308 /* Start the cdrom drive */ #define CDROMEJECT 0x5309 /* Ejects the cdrom media */ #define CDROMVOLCTRL 0x530a /* Control output volume #define CDROMSUBCHNL 0x530b /* Read subchannel data #define CDROMREADMODE2 0x530c /* Read CDROM mode 2 data (2336 Bytes) #define CDROMREADMODE1 0x530d /* Read CDROM mode 1 data (2048 Bytes) #define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ #define CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */ #define CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session #define CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" #define CDROM_GET_UPC CDROM_GET_MCN /* This one is deprecated, #define CDROMRESET 0x5312 /* hard-reset the drive */ #define CDROMVOLREAD 0x5313 /* Get the drive's volume setting #define CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes) #define CDROMREADCOOKED 0x5315 /* read data in cooked mode */ #define CDROMSEEK 0x5316 /* seek msf address */ #define CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ #define CDROMREADALL 0x5318 /* read all 2646 bytes */ #define CDROMGETSPINDOWN 0x531d #define CDROMSETSPINDOWN 0x531e #define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */ #define CDROM_SET_OPTIONS 0x5320 /* Set behavior options */ #define CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */ #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */ #define CDROM_SELECT_DISC 0x5323 /* Select disc (for juke-boxes) */ #define CDROM_MEDIA_CHANGED 0x5325 /* Check is media changed */ #define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */ #define CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */ #define CDROM_CHANGER_NSLOTS 0x5328 /* Get number of slots */ #define CDROM_LOCKDOOR 0x5329 /* lock or unlock door */ #define CDROM_DEBUG 0x5330 /* Turn debug messages on/off */ #define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ #define CDROM_SEND_PACKET 0x5393 /* send a packet to the drive */ #define CDROM_NEXT_WRITABLE 0x5394 /* get next writable block */ #define CDROM_LAST_WRITTEN 0x5395 /* get last block written on disc */ ====== the above sample we focus on kernel 2.6 and for those of you who getting interested for kernel 3.0 cdrom programing, you may also find uselful material at: ============== http://www.mjmwired.net/kernel/Documentation/ioctl/cdrom.txt ============== on success our ioctl function will return other than -1 !!! 2. ioctl on socket we also may use an ioctl syscall related to socket. as i've mentioned above the call for ioctl : ioctl(any_file_descriptor, any_command, etc...). in socket operation circumstances we've some common categories such as: ======== * Socket, an ioctl request for controlling socket , ex cmd: SIOCATMARK, etc * Routing table, an ioctl req related to kernel routing table, ex: SIOCADDRT , SIOUPDROUTE, etc * ARP table, an ioctl req for modifying arp table, ex: SIOCSARP , SIOCDARP , etc * Interface, an ioctl req related to interface on ur fvcking system, ex: SIOCSIFADDR (getting interface name), etc ============= you can read more at /usr/include/bits/ioctls.h : ======================================== /* Socket configuration controls. */ #define SIOCGIFNAME 0x8910 /* get iface name */ #define SIOCSIFLINK 0x8911 /* set iface channel */ #define SIOCGIFCONF 0x8912 /* get iface list */ #define SIOCGIFFLAGS 0x8913 /* get flags */ #define SIOCSIFFLAGS 0x8914 /* set flags */ #define SIOCGIFADDR 0x8915 /* get PA address */ #define SIOCSIFADDR 0x8916 /* set PA address */ #define SIOCGIFDSTADDR 0x8917 /* get remote PA address */ #define SIOCSIFDSTADDR 0x8918 /* set remote PA address */ #define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ #define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ #define SIOCGIFNETMASK 0x891b /* get network PA mask */ #define SIOCSIFNETMASK 0x891c /* set network PA mask */ #define SIOCGIFMETRIC 0x891d /* get metric */ #define SIOCSIFMETRIC 0x891e /* set metric */ #define SIOCGIFMEM 0x891f /* get memory address (BSD) */ #define SIOCSIFMEM 0x8920 /* set memory address (BSD) */ #define SIOCGIFMTU 0x8921 /* get MTU size */ #define SIOCSIFMTU 0x8922 /* set MTU size */ #define SIOCSIFNAME 0x8923 /* set interface name */ #define SIOCSIFHWADDR 0x8924 /* set hardware address */ #define SIOCGIFENCAP 0x8925 /* get/set encapsulations */ #define SIOCSIFENCAP 0x8926 #define SIOCGIFHWADDR 0x8927 /* Get hardware address */ #define SIOCGIFSLAVE 0x8929 /* Driver slaving support */ #define SIOCSIFSLAVE 0x8930 #define SIOCADDMULTI 0x8931 /* Multicast address lists */ #define SIOCDELMULTI 0x8932 #define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */ #define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */ #define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */ #define SIOCGIFPFLAGS 0x8935 #define SIOCDIFADDR 0x8936 /* delete PA address */ #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ #define SIOCGIFCOUNT 0x8938 /* get number of devices */ #define SIOCGIFBR 0x8940 /* Bridging support */ #define SIOCSIFBR 0x8941 /* Set bridging options */ #define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ #define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ and so on............... =============================== [Interface] ok when u wanna play with interface u must knowing some important structs and constants related to our fvcking interfaces, check this out: some codes from /usr/include/net/if.h: ==================================== struct ifreq { # define IFHWADDRLEN 6 # define IFNAMSIZ IF_NAMESIZE union { char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */ } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short int ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; __caddr_t ifru_data; } ifr_ifru; }; # define ifr_name ifr_ifrn.ifrn_name /* interface name */ # define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ # define ifr_addr ifr_ifru.ifru_addr /* address */ # define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ # define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ # define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ # define ifr_flags ifr_ifru.ifru_flags /* flags */ # define ifr_metric ifr_ifru.ifru_ivalue /* metric */ # define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ # define ifr_map ifr_ifru.ifru_map /* device map */ # define ifr_slave ifr_ifru.ifru_slave /* slave device */ # define ifr_data ifr_ifru.ifru_data /* for use by interface */ # define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ # define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ # define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */ # define ifr_newname ifr_ifru.ifru_newname /* New name */ # define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0) # define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0) # define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0) struct ifconf { int ifc_len; /* Size of buffer. */ union { __caddr_t ifcu_buf; struct ifreq *ifcu_req; } ifc_ifcu; }; # define ifc_buf ifc_ifcu.ifcu_buf /* Buffer address. */ # define ifc_req ifc_ifcu.ifcu_req /* Array of structures. */ # define _IOT_ifconf _IOT(_IOTS(struct ifconf),1,0,0,0,0) /* not right */ #endif /* Misc. */ ====================================== or u can see use this cmd at ur fvcking shell: man netdevice ok so we're gonna use those 2 fvcking struct, here we go with our c: =================== struct ifreq *pIfr; struct ifconf ifc; =================== here more complete where we're gonna use to view our interface when we've created our socket file desc: =========== /***this code taken from http://stackoverflow.com/questions/4961051/find-network-interfaces-that-are-not-running**/ #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> #include <net/if.h> #include <arpa/inet.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { struct ifreq *pIfr; struct ifconf ifc; char buf[1024]; int s, i, j; s = socket(AF_INET, SOCK_DGRAM, 0); if (s==-1) return -1; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; ioctl(s, SIOCGIFCONF, &ifc); pIfr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; pIfr++) { printf("name=%s\n", pIfr->ifr_name); } close(s); return 0; } ============== as you see, the result will be somethin like tis: ========== mywisdom@mywisdom-Vostro1310:~/c/ioctl$ gcc -o soket2 soket2.c mywisdom@mywisdom-Vostro1310:~/c/ioctl$ ./socket2 bash: ./socket2: No such file or directory mywisdom@mywisdom-Vostro1310:~/c/ioctl$ ./soket2 name=lo name=eth0 ========== ok let's have a look on some important lines: on s = socket(AF_INET, SOCK_DGRAM, 0); it's where we prepare an open socket file descriptor ======= ifc.ifc_len = sizeof(buf); ======== as u may see on our ifconf struct: ===================== struct ifconf { int ifc_len; /* Size of buffer. */ ===================== as we've declared the struct before: struct ifconf ifc; so ifc.ifc_len will be 1024 bytes the most importand line on our ioctl request on that open socket file desc: ================ ioctl(s, SIOCGIFCONF, &ifc); ================ where we use this command: SIOCGIFCONF to get iface lists =============== mywisdom@mywisdom-Vostro1310:~/c/ioctl$ cat /usr/include/bits/ioctls.h | grep SIOCGIFCONF #define SIOCGIFCONF 0x8912 /* get iface list */ =============== and final important step is when we do a for loop to get pIfr->ifr_name: ================== pIfr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; pIfr++) { printf("name=%s\n", pIfr->ifr_name); } ============== [modifying linux kernel routing table] have a look at ur linux kernel ip routing table: ============================ mywisdom@mywisdom-Vostro1310:~/c/ioctl$ route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 111.**.**.* * 255.255.255.0 U 1 0 0 eth0 link-local * 255.255.0.0 U 1000 0 0 eth0 default 111.**.**.* 0.0.0.0 UG 0 0 0 eth0 mywisdom@mywisdom-Vostro1310:~/c/ioctl$ cat /proc/net/arp IP address HW type Flags HW address Mask Device 111.**.**.* 0x1 0x2 *************** * eth0 root@mywisdom-Vostro1310:/home/mywisdom/c/ioctl# /usr/sbin/arp -a ? (111.**.**.*) at c4:**:**:**:**:** [ether] on eth0 well the cmd :"arp -a" reads from /dev/kmem to get the cache ok we've some cmd's on our ioctl related to this arp game: - SIOCSARP --- ioctl request intended to add an entry to our fvcking arp table - SIOCDARP -- D==delete means our fvcking ioctl request is intended to delete an entry for our fvcking arp table - SIOCGARP -- G= get means our fvcking ioctl request is intended to get an entry from our fvcking arp table for SIOCSARP and SIOCDARP u need root privileges and for SIOCGARP u don't need root privilege the first one to do is getting an entry from the kernel IP routing table, so we'll need ioctl(fd, SIOCGARP,arg). you need to have a visit on /usr/include/net/if_arp.h to understand =========== root@mywisdom-Vostro1310:/home/mywisdom/c/ioctl# cat /usr/include/net/if_arp.h /* Based on the 4.4BSD and Linux version of this file. */ #ifndef _NET_IF_ARP_H #define _NET_IF_ARP_H 1 #include <sys/cdefs.h> #include <sys/types.h> #include <sys/socket.h> __BEGIN_DECLS /* Some internals from deep down in the kernel. */ #define MAX_ADDR_LEN 7 /* This structure defines an ethernet arp header. */ /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request. */ #define ARPOP_REPLY 2 /* ARP reply. */ #define ARPOP_RREQUEST 3 /* RARP request. */ #define ARPOP_RREPLY 4 /* RARP reply. */ #define ARPOP_InREQUEST 8 /* InARP request. */ #define ARPOP_InREPLY 9 /* InARP reply. */ #define ARPOP_NAK 10 /* (ATM)ARP NAK. */ /* See RFC 826 for protocol description. ARP packets are variable in size; the arphdr structure defines the fixed-length portion. Protocol type values are the same as those for 10 Mb/s Ethernet. It is followed by the variable-sized fields ar_sha, arp_spa, arp_tha and arp_tpa in that order, according to the lengths specified. Field names used correspond to RFC 826. */ struct arphdr { unsigned short int ar_hrd; /* Format of hardware address. */ unsigned short int ar_pro; /* Format of protocol address. */ unsigned char ar_hln; /* Length of hardware address. */ unsigned char ar_pln; /* Length of protocol address. */ unsigned short int ar_op; /* ARP opcode (command). */ #if 0 /* Ethernet looks like this : This bit is variable sized however... */ unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */ unsigned char __ar_sip[4]; /* Sender IP address. */ unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */ unsigned char __ar_tip[4]; /* Target IP address. */ #endif }; /* ARP protocol HARDWARE identifiers. */ #define ARPHRD_NETROM 0 /* From KA9Q: NET/ROM pseudo. */ #define ARPHRD_ETHER 1 /* Ethernet 10/100Mbps. */ #define ARPHRD_EETHER 2 /* Experimental Ethernet. */ #define ARPHRD_AX25 3 /* AX.25 Level 2. */ #define ARPHRD_PRONET 4 /* PROnet token ring. */ #define ARPHRD_CHAOS 5 /* Chaosnet. */ #define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB. */ #define ARPHRD_ARCNET 7 /* ARCnet. */ #define ARPHRD_APPLETLK 8 /* APPLEtalk. */ #define ARPHRD_DLCI 15 /* Frame Relay DLCI. */ #define ARPHRD_ATM 19 /* ATM. */ #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id). */ #define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734. */ #define ARPHRD_EUI64 27 /* EUI-64. */ #define ARPHRD_INFINIBAND 32 /* InfiniBand. */ /* Dummy types for non ARP hardware */ #define ARPHRD_SLIP 256 #define ARPHRD_CSLIP 257 #define ARPHRD_SLIP6 258 #define ARPHRD_CSLIP6 259 #define ARPHRD_RSRVD 260 /* Notional KISS type. */ #define ARPHRD_ADAPT 264 #define ARPHRD_ROSE 270 #define ARPHRD_X25 271 /* CCITT X.25. */ #define ARPHRD_HWX25 272 /* Boards with X.25 in firmware. */ #define ARPHRD_PPP 512 #define ARPHRD_CISCO 513 /* Cisco HDLC. */ #define ARPHRD_HDLC ARPHRD_CISCO #define ARPHRD_LAPB 516 /* LAPB. */ #define ARPHRD_DDCMP 517 /* Digital's DDCMP. */ #define ARPHRD_RAWHDLC 518 /* Raw HDLC. */ #define ARPHRD_TUNNEL 768 /* IPIP tunnel. */ #define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel. */ #define ARPHRD_FRAD 770 /* Frame Relay Access Device. */ #define ARPHRD_SKIP 771 /* SKIP vif. */ #define ARPHRD_LOOPBACK 772 /* Loopback device. */ #define ARPHRD_LOCALTLK 773 /* Localtalk device. */ #define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface. */ #define ARPHRD_BIF 775 /* AP1000 BIF. */ #define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4. */ #define ARPHRD_IPDDP 777 /* IP-in-DDP tunnel. */ #define ARPHRD_IPGRE 778 /* GRE over IP. */ #define ARPHRD_PIMREG 779 /* PIMSM register interface. */ #define ARPHRD_HIPPI 780 /* High Performance Parallel I'face. */ #define ARPHRD_ASH 781 /* (Nexus Electronics) Ash. */ #define ARPHRD_ECONET 782 /* Acorn Econet. */ #define ARPHRD_IRDA 783 /* Linux-IrDA. */ #define ARPHRD_FCPP 784 /* Point to point fibrechanel. */ #define ARPHRD_FCAL 785 /* Fibrechanel arbitrated loop. */ #define ARPHRD_FCPL 786 /* Fibrechanel public loop. */ #define ARPHRD_FCFABRIC 787 /* Fibrechanel fabric. */ #define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR. */ #define ARPHRD_IEEE80211 801 /* IEEE 802.11. */ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header. */ #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header. */ #define ARPHRD_IEEE802154 804 /* IEEE 802.15.4 header. */ #define ARPHRD_IEEE802154_PHY 805 /* IEEE 802.15.4 PHY header. */ #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known. */ #define ARPHRD_NONE 0xFFFE /* Zero header length. */ /* ARP ioctl request. */ struct arpreq { struct sockaddr arp_pa; /* Protocol address. */ struct sockaddr arp_ha; /* Hardware address. */ int arp_flags; /* Flags. */ struct sockaddr arp_netmask; /* Netmask (only for proxy arps). */ char arp_dev[16]; }; /* ARP Flag values. */ #define ATF_COM 0x02 /* Completed entry (ha valid). */ #define ATF_PERM 0x04 /* Permanent entry. */ #define ATF_PUBL 0x08 /* Publish entry. */ #define ATF_USETRAILERS 0x10 /* Has requested trailers. */ #define ATF_NETMASK 0x20 /* Want to use a netmask (only for proxy entries). */ #define ATF_DONTPUB 0x40 /* Don't answer this addresses. */ #define ATF_MAGIC 0x80 /* Automatically added entry. */ /* Support for the user space arp daemon, arpd. */ #define ARPD_UPDATE 0x01 #define ARPD_LOOKUP 0x02 #define ARPD_FLUSH 0x03 struct arpd_request { unsigned short int req; /* Request type. */ u_int32_t ip; /* IP address of entry. */ unsigned long int dev; /* Device entry is tied to. */ unsigned long int stamp; unsigned long int updated; unsigned char ha[MAX_ADDR_LEN]; /* Hardware address. */ }; __END_DECLS #endif /* net/if_arp.h */ ===================== we'll use this struct: ============= struct arpreq { struct sockaddr arp_pa; /* Protocol address. */ struct sockaddr arp_ha; /* Hardware address. */ int arp_flags; /* Flags. */ struct sockaddr arp_netmask; /* Netmask (only for proxy arps). */ char arp_dev[16]; }; ============= ok let's have a sample code that use this SIOCGARP ioctl, well as a sample of this func usage is to find our gateway mac addr . don't forget to include the header needed: ================= #include <errno.h> #include <stdio.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if_arp.h> #include <netinet/in.h> #include <linux/sockios.h> #include <unistd.h> #include <string.h> #include <stdlib.h> ==================== u should already notice that we've use: #include <net/if_arp.h> to include our arp struct here are 3 structs that we are gonna use: ============ struct arpreq areq; struct sockaddr_in *sin; struct in_addr ipaddr; ============ where in order to execute ioctl SIOCGARP properly we need this struct: struct arpreq areq; the code was taken from http://forums.devshed.com/c-programming-42/how-to-get-properly-ehternet-mac-address-with-siocgarp-request-171811.html gatewaymac.c : ============================ /**taken from http://forums.devshed.com/c-programming-42/how-to-get-properly-ehternet-mac-address-with-siocgarp-request-171811.html **/ #include <errno.h> #include <stdio.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if_arp.h> #include <netinet/in.h> #include <linux/sockios.h> #include <unistd.h> #include <string.h> #include <stdlib.h> static char *ethernet_mactoa(struct sockaddr *addr) { static char buff[256]; unsigned char *ptr = (unsigned char *) addr->sa_data; sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)); return (buff); } int main(int argc, char *argv[]) { int s; struct arpreq areq; struct sockaddr_in *sin; struct in_addr ipaddr; if (argc < 2 || argc > 2) { fprintf(stderr, "-- Usage: %s ipaddress\n", argv[0]); exit(1); } /* Get an internet domain socket. */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1); } /* Make the ARP request. */ memset(&areq, 0, sizeof(areq)); sin = (struct sockaddr_in *) &areq.arp_pa; sin->sin_family = AF_INET; if (inet_aton(argv[1], &ipaddr) == 0) { fprintf(stderr, "-- Error: invalid numbers-and-dots IP address %s.\n", argv[1]); exit(1); } sin->sin_addr = ipaddr; sin = (struct sockaddr_in *) &areq.arp_ha; sin->sin_family = ARPHRD_ETHER; strncpy(areq.arp_dev, "eth0", 15); if (ioctl(s, SIOCGARP, (caddr_t) &areq) == -1) { perror("-- Error: unable to make ARP request, error"); exit(1); } printf("%s (%d) -> %s\n", argv[1], inet_ntoa(&((struct sockaddr_in *) &areq.arp_pa)->sin_addr), ethernet_mactoa(&areq.arp_ha)); return 0; } =========================== let's have a check on our gateway's mac address: =========== root@mywisdom-Vostro1310:/home/mywisdom/c/ioctl# ./gatewaymac 111.**.**.* 111.**.**.* -> C4:**:**:**:**:**