IntelliJのremote interpreter方式を使って、Raspbian上のScapyをリモートデバッグしてみた

Raspberry Pi 2 Model BでScapyを書いていると、リモートデバッグしたくなりました。

そこで、IntelliJのremote interpreter方式を使って、Raspbian上のScapyをリモートデバッグしてみた時のメモを残します。

 
目次

 

環境

 

公開鍵を使ったSSHを可能にするよう設定

以前、

pi@raspberrypi:~ $ sudo raspi-config

から 5 Interfacing Options > P2 SSH にて enabled してありますので、その設定の続きです。

 
今回は、以下を参考に実施しました。
ツール・ラボ » Raspberry Piに公開鍵認証を使ってssh接続する

なお、今回はパスワード認証もとりあえず残しておきます。

以下ログです。  

# Macにてキーペアの作成
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_raspberry_pi

# scpにてMacからラズパイへ公開鍵を転送
$ scp -P 22 ~/.ssh/id_rsa_raspberry_pi.pub pi@192.168.10.50:
pi@192.168.10.50's password: 
id_rsa_raspberry_pi.pub                        

# ラズパイにて転送されていることを確認
pi@raspberrypi:~ $ ls -al id*
-rw-r--r-- 1 pi pi 757 Jan  7 13:49 id_rsa_raspberry_pi.pub

# 鍵を移動して権限を設定
pi@raspberrypi:~ $ mkdir .ssh
pi@raspberrypi:~ $ cat id_rsa_raspberry_pi.pub >> .ssh/authorized_keys
pi@raspberrypi:~ $ chmod 700 .ssh
pi@raspberrypi:~ $ chmod 600 .ssh/authorized_keys

# 末尾に追加
pi@raspberrypi:~ $ sudo vi /etc/ssh/sshd_config
# 以下3行を追加
RSAAuthentication    yes
PubkeyAuthentication yes
AuthorizedKeysFile   %h/.ssh/authorized_keys

# 不要な公開鍵を削除してSSHを再起動
pi@raspberrypi:~ $ rm id_rsa_raspberry_pi.pub  
pi@raspberrypi:~ $ sudo /etc/init.d/ssh restart
[ ok ] Restarting ssh (via systemctl): ssh.service.

# Macより公開鍵認証でSSHできることを確認
$ ssh -i ~/.ssh/id_rsa_raspberry_pi pi@192.168.10.50
Linux raspberrypi 4.9.59-v7+ #1047 SMP Sun Oct 29 12:19:23 GMT 2017 armv7l
...
pi@raspberrypi:~ $ 

 

IntelliJを使ったリモートデバッグ設定

IntelliJのリモートデバッグには

の2つがあるようです。
PyCharmのリモートデバッグ機能を使ってみる - Qiita

 
今回は、以下を参考にSSHを使うremote interpreter方式を使ってみました。
PyCharmを使ってRaspberry Pi2上で快適リモートGPIOプログラミング - izm_11's blog

 
以下、作業ログです。

  • 既存のScapyプロジェクトを開く
  • Project Structureを開く
    • File > Project Structure
  • Python SDKをローカルから切り替える
    • Project > Project SDK > New > Python SDK > Add Remote
  • リモート設定は以下
項目 設定値
接続方式 SSH Credentials
Host 192.168.10.50 (必要に応じて差し替え)
User name pi
Auth type Key pair (OpenSSH or PuTTY)
Private key file /path/to/.ssh/id_rsa_raspberry_pi
Python interpreter path /usr/bin/python (デフォルト値)

 

  • パスマッピングを実施
    • メニューの Tools > Deployment > Configuration
    • 左上の + ボタン
    • 設定内容は以下
タブ 設定 項目値
Connection Name (任意の名前)
Visible only for this project チェックする
Type SFTP
SFTP Host 192.168.10.50
Port 22
Path /
User name pi
Auth type Key pair (OpenSSH or PuTTY)
Private key file /path/to/.ssh/id_rsa_raspberry_pi
Mappings Local path /path/to/マッピング
Deployment path on server /home/pi/scapy_sample

 

  • ファイルのアップロード
    • アップロードしたいファイルを開いた状態で、 Tools > Deployment > Upload to <サーバ名>
    • ディレクトリ階層があれば、その階層も含めてアップロードされる
  • アップロードの自動化
    • Tools > Deployment > Automatic Upload にチェックを入れる

 
以上で、Macとラズパイとでファイルの同期が取れるようになりました。

 

Scapyのための設定変更

今回は、以前使用したDHCPサーバを探すファイルをリモートデバッグしてみます。
https://github.com/thinkAmi-sandbox/scapy-sample/blob/master/dhcp/discover_dhcp_server.py

まず、ラズパイ上で実行するため、インタフェース名を変更しておきます。

USB_INTERFACE_NAME = 'eth0'

 
また、Scapyを実行するにはsudoする必要があります。ただ、通常のリモートデバッグではsudoした状態にはなりません。

そこで今回は、システムのPythonの権限まわりを変更しました。
Remote Debug GPIO on Raspberry Pi | Nathan Jones

あまり良くないのかもしれませんが、ラズパイということで今回は気にしないことにします。

pi@raspberrypi:~ $ sudo chown -v root:root /usr/bin/python
ownership of '/usr/bin/python' retained as root:root

pi@raspberrypi:~ $ sudo chmod -v u+s /usr/bin/python
mode of '/usr/bin/python' changed from 0755 (rwxr-xr-x) to 4755 (rwsr-xr-x)

 

リモートデバッグの実行

まずは、上記で変更を加えたファイルをラズパイへ転送します。

ブレークポイントを置いてデバッグ実行してみると、ブレークポイントで停止しました。

f:id:thinkAmi:20180110222702p:plain:w400

 
デバッグを続行すると、コンソールに以下が表示されました。

なお、DHCPサーバを探すためのパケット送信が止まらないので、 Cmd + F2 で止める必要があります。

ssh://pi@192.168.10.50:22/usr/bin/python -u /home/pi/.pycharm_helpers/pydev/pydevd.py --cmd-line --multiproc --qt-support=auto --client '0.0.0.0' --port 36797 --file /home/pi/scapy_sample/dhcp/discover_dhcp_server.py
pydev debugger: process 1661 is connecting

Connected to pydev debugger (build 173.4127.27)
###[ Ethernet ]### 
  dst       = FF:FF:FF:FF:FF:FF
  src       = 00:00:00:00:00:04
  type      = 0x800
###[ IP ]### 
     version   = 4
     ihl       = None
     tos       = 0x0
     len       = None
     id        = 1
     flags     = 
     frag      = 0
     ttl       = 64
     proto     = udp
     chksum    = None
     src       = 0.0.0.0
     dst       = 255.255.255.255
     \options   \
###[ UDP ]### 
        sport     = bootpc
        dport     = bootps
        len       = None
        chksum    = None
###[ BOOTP ]### 
           op        = BOOTREQUEST
           htype     = 1
           hlen      = 6
           hops      = 0
           xid       = 0
           secs      = 0
           flags     = 
           ciaddr    = 0.0.0.0
           yiaddr    = 0.0.0.0
           siaddr    = 0.0.0.0
           giaddr    = 0.0.0.0
           chaddr    = '\x00\x00\x00\x00\x00\x04'
           sname     = ''
           file      = ''
           options   = 'c\x82Sc'
###[ DHCP options ]### 
              options   = [message-type='discover' end]

................Begin emission:
Finished to send 1 packets.
....................................*.................................................................................^C
Received 134 packets, got 1 answers, remaining 0 packets
DHCP Server - MAC: a4:xx:xx:xx:xx:xx, IP: 192.168.10.1

 

ラズパイへ接続できない環境での注意点

ラズパイへ接続できない環境へ移動して、リモートデバッグ設定をしたプロジェクトを開くと、

Couldn't refresh skeletons for remote interpreter: Error connecting to remote host 192.168.10.50

というメッセージが表示されました。

また、 Automatic update を有効にしていると、ラズパイへの接続を常に探しているようでした。その結果、ファンが回りっぱなしになるなど、負荷の高まりを感じました。

 
そのため、ラズパイへ接続できない環境へ移動した場合は、

  • Python SDKを、Remoteからローカルのものに切り替える
  • Automatic Updateを解除する

などを行ったほうが良さそうです。