読者です 読者をやめる 読者になる 読者になる

ClojureでMagicPacket送信ツールを作ってみた

Clojureで書くとこんな感じかな。

(ns
    #^{:author "otabat",
       :doc "Magic packet sender"}
  masquerade
  (:gen-class))

(import '(java.net InetSocketAddress DatagramPacket DatagramSocket))
(use '[clojure.contrib.str-utils :only (re-split)])

(def default-port 2304)
(def buf-length 102)

(defn send-magic-packet
  "Send magic packet to specified host"
  [ip port mac-byte]
  (let [mac-byte-array (into-array (Byte/TYPE) mac-byte)
	sock (DatagramSocket.)
	host-addr (InetSocketAddress. ip port)
	packet (DatagramPacket. mac-byte-array buf-length host-addr)]
    (.setBroadcast sock true)
    (.send sock packet)))

(defn repeat-seq
  [n buf]
  (loop [res '() i n]
    (if (zero? i)
      res
      (recur (concat res buf) (dec i)))))

(defn string-hex-to-byte-digit
  [mac]
  (for [x (re-split #":" mac)] (byte (Integer/parseInt x 16))))

(defn is-port
  "Determine whether it is a valid port number."
  [port]
  (and (>= port 0)
       (<= port 65535)))

(defn is-mac
  "Determine whether it is a valid mac address."
  [mac]
  (let [patn "^((([a-fA-F0-9]){2}):){5}([a-fA-F0-9]){2}$"]
    (and (= mac
	    (first (re-find (re-pattern patn) mac))))))

(defn is-ip
  "Determine whether it is a valid ip address."
  [ip]
  (let [p "(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])"
	patn (str "^" p "\\." p "\\." p "\\." p "$")]
    (and (= ip
	    (first (re-find (re-pattern patn) ip))))))

(defn -main
  [ip mac port]
  (let [port (Integer/parseInt port)
	buf (repeat 6 (byte 0xff))]
    (when-not
	(and (is-ip ip)
	     (is-mac mac)
	     (is-port port))
      (println "Invalid input.")
      (System/exit 0))
    (let [mac-byte (string-hex-to-byte-digit mac)
	  buf (concat buf (repeat-seq 16 mac-byte))]
      (send-magic-packet ip port buf))))

ついでにビルド方法も。
Leiningen使ってる人は以下のようにやればOK。

$ lein compile
     [null] Compiling masquerade
$ lein uberjar
All :namespaces already compiled.
Created /プロジェクトのパス/masquerade.jar
Including masquerade.jar
Including clojure-1.1.0-master-20091231.150150-10.jar
Including clojure-contrib-1.1.0-master-20100114.180141-21.jar

最後に起動方法。

$ java -jar masquerade-standalone.jar xxx.xxx.xxx.xxx MM:MM:MM:MM:MM:MM 2304