amazon dash buttonのハック


はじめに

n番煎じのamazon dash buttonを万能ボタン化する話

node.jsのライブラリがすでに開発されていましたが,

Mac環境前提だったり, 不勉強でnpmよくわからなかったりと

苦労が多かったので, c++で自作しました

作ったコードはgithubにあげてあります

どういう処理をしてるかはこの記事で説明していて,

使い方はgithubのREADME.mdに書いています


amazon dash buttonの簡単な仕組み

amazon dash buttonはボタンを押すだけで注文してくれる便利?ボタンです

スマホによって設定したwifi下で作動します

詳しい仕組みは省きますが, arpという送信先を限定しない通信方式で, ルーターにリクエストを送信しています

最後まで設定をしない状態でボタンを押すと, リクエストを送信するが, 注文はされないという状態になります

ボタンをこの状態にしておき, 同じwifi内のサーバでボタンによるリクエストを受信することで, なんらかのアクションを発火させることができます


amazon dash buttonの受信

まず, amazon dash buttonのMACアドレスを調べます

Wireshark等のパケットキャプチャソフトを使うか,

github内にあるarpパケットを受信するスクリプトで調べることができます

次に, arpパケットを受信し, MACアドレスの照会をします

エラー処理を省略した簡単なコードを乗せておきます


arpの受信処理

    /*arp用のソケットを作り, bindする*/

int arp_sock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
struct sockaddr_ll sockaddr;
memset(&sockaddr, 0x0, sizeof(sockaddr));
sockaddr.sll_family = AF_PACKET;
sockaddr.sll_protocol = htons(ETH_P_ARP);
sockaddr.sll_ifindex = if_nametoindex("eth0");
bind(arp_sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr))

/*ソケットにarp通信を受信*/
char buf[256];
memset(buf,0x0,sizeof(buf));
int arp_size = recvfrom(arp_sock, buf, sizeof(buf), 0, NULL, NULL);

/*ソケットをキャスト*/
struct ether_arp *arppack = (struct ether_arp*) buf;



ether_arpの実体

struct ether_arp {

u_int16 arp_hrd;
u_int16 arp_pro;
u_int8 arp_hln;
u_int8 arp_pln
u_int8 arp_sha[6];
u_int32 arp_spa;
u_int8 arp_tha[6];
u_int32 arp_tpa;
};

struct ether_arp内のarp_sha[6]が受信したarpソケットのMACアドレスになります

これを事前に調べたMACアドレスと照会して, 一致すれば何らかのアクションを発火します


Webhooks

他の多くのamazon dash buttonハック系の記事と同様に, 何らかのアクションとして組み込んだのがWebhooksというサービスです

Webhooksは, 登録したURLにHTTPリクエストを送ることで, 別のアプリに通知を送ることができます

細かい設定は省略しますが, LINE, VoIP, slackをそれぞれ通知先に設定しました

サイトで設定すると, サンプルにcurlのスクリプトを出してくれるので, それをそのままシステム関数でコールしています

githubでは, Makeのtargetを変えることで, ボタンの通知先を切り替えています


実際の動画

ボタンで発火するアクションをLINEの通知にしたversionの動画です

gifのレート下げてて見にくいですが, 多少の遅延があります


like.gif


おわりに

amazon dash buttonでアクションを発火させることはできましたが,

何を発火させるかという部分の想像力が足りませんでした...

結局, LINE, Slackに固定文を送るボタンになりそうです


余談(環境構築)

最初はWSLで使おうとしてましたが,

tcpdumpやソケット作成ができなかったので,

VM上のUbuntuで動作するようにしました

VM上のOSで外部ネットワーク情報を知るには,

VMのネットワーク設定をNATではなく,

ホストオンリーアダプタかブリッジアダプタに設定する

必要があるので, 注意しましょう


参考にしたサイト

https://blanktar.jp/blog/2013/04/ethernet-header.html

http://jis.hatenablog.com/entry/2013/09/20/143655