三月 17

WordPress 的 SyntaxHighlighter-Plus 外掛預設支援下列的語言

* Bash -- `bash`, `sh`
* C++ -- `cpp`, `c`, `c++`
* C# -- `c#`, `c-sharp`, `csharp`
* CSS -- `css`
* Delphi -- `delphi`, `pascal`
* Diff -- `diff`, `patch`
* Groovy -- `groovy`
* Java -- `java`
* JavaScript -- `js`, `jscript`, `javascript`
* PHP -- `php`
* Plain text -- `plain`, `text`
* Python -- `py`, `python`
* Ruby -- `rb`, `ruby`, `rails`, `ror`
* SQL -- `sql`
* VB -- `vb`, `vbnet`, `vb.net`
* XML/HTML -- `xml`, `html`, `xhtml`, `xslt`

如果今天想要加入一個新的語言該怎麼怎做呢?

只要2個步驟就可以完成了

1.把適用於SyntaxHighlighter-Plus的語言樣版(JavaScript)放到
/wp-content/plugins/syntaxhighlighter-plus/syntaxhighlighter/scripts

2.編輯/wp-content/plugins/syntaxhighlighter-plus/syntaxhighlighter.php
大約在在112行的位置加入樣版的名子

$this->aliases = apply_filters( 'agsyntaxhighlighter_aliases', array(
'Bash' => array('bash', 'sh', 'shell'),
'Cpp' => array('cpp', 'c', 'c++'),

例如要加入一個批次檔(bat)的樣版,把下面這行加入

'Batch' => array('batch','dos','bat'),

加入後變成

$this->aliases = apply_filters( 'agsyntaxhighlighter_aliases', array(
'Bash' => array('bash', 'sh', 'shell'),
'Batch' => array('batch','dos','bat'),
'Cpp' => array('cpp', 'c', 'c++'),

下面我們用例子來看看。

如果要加入Dos批次檔與Perl的語法樣版

首先,先把下面2個JavaScrip放到

/wp-content/plugins/syntaxhighlighter-plus/syntaxhighlighter/scripts

程式碼另存為shBrushBatch.js

/*shBrushBatch.js*/

SyntaxHighlighter.brushes.Batch = function()
{

var keywords =  'do else for in call choice goto shift pause errorlevel ' +
'if not exist lfnfor start setlocal endlocal echo set';

var commands =  'append attrib cd chdir chkdsk choice cls copy del erase deltree ' +
'dir exit fc comp fdisk find format fsutil help join ' +
'label loadfix md mkdir mem memmaker more move msd pcpark ' +
'print rd rmdir ren scandisk share sort subst sys ' +
'time date tree truename type undelete ver xcopy';

this.regexList = [
{ regex: SyntaxHighlighter.regexLib.singleLinePerlComments,             css: 'comments' },              // one line comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString,                 css: 'string' },                // double quoted strings
{ regex: new RegExp(this.getKeywords(keywords), 'gm'),                  css: 'keyword' },               // keywords
{ regex: new RegExp(this.getKeywords(commands), 'gm'),                  css: 'functions' }              // commands
];
}

SyntaxHighlighter.brushes.Batch.prototype       = new SyntaxHighlighter.Highlighter();
SyntaxHighlighter.brushes.Batch.aliases         = ['dos', 'batch', 'bat'];

程式碼另存為shBrushPerl.js

</span></span>

程式碼另存為shBrushPerl.js

[code='js']

/*shBrushPerl.js*/

SyntaxHighlighter.brushes.Perl = function()
{
var funcs = 'abs accept alarm atan2 bind binmode bless caller chdir chmod chomp chop chown chr chroot close closedir connect cos crypt dbmclose dbmopen defined delete dump each endgrent endhostent endnetent endprotoent endpwent endservent eof exec exists exp fcntl fileno flock fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getppid getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt glob gmtime grep hex import index int ioctl join keys kill lc lcfirst length link listen localtime lock log lstat m map mkdir msgctl msgget msgrcv msgsnd no oct open opendir ord pack pipe pop pos print printf prototype push q qq quotemeta qw qx rand read readdir readline readlink readpipe recv ref rename reset reverse rewinddir rindex rmdir scalar seek seekdir semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unlink unpack unshift untie utime values vec waitpid wantarray warn write qr';

var keywords =  's select goto die do package redo require return continue for foreach last next wait while use if else elsif eval exit unless switch case';

var constants   = 'my our local';

this.regexList = [
{ regex: SyntaxHighlighter.regexLib.singleLineCComments,        css: 'comments' },                      // one line comments
{ regex: SyntaxHighlighter.regexLib.multiLineCComments,         css: 'comments' },                      // multiline comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString,         css: 'string' },                        // double quoted strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString,         css: 'string' },                        // single quoted strings
{ regex: /\$\w+/g,                                                                                      css: 'variable' },                      // variables
{ regex: new RegExp(this.getKeywords(funcs), 'gmi'),            css: 'functions' },                     // common functions
{ regex: new RegExp(this.getKeywords(constants), 'gmi'),        css: 'constants' },                     // constants
{ regex: new RegExp(this.getKeywords(keywords), 'gm'),          css: 'keyword' }                        // keyword
];

this.forHtmlScript(SyntaxHighlighter.regexLib.phpScriptTags);
};
SyntaxHighlighter.brushes.Perl.prototype = new SyntaxHighlighter.Highlighter();
SyntaxHighlighter.brushes.Perl.aliases  = ['perl','pl'];

最後在 /wp-content/plugins/syntaxhighlighter-plus/syntaxhighlighter.php 加入

'Batch' => array('batch','dos','bat'),
'Perl' => array('perl', 'pl'),

大功告成

參考資料:
shBrushBatch for Google SyntaxHighlighter
Perl Syntax Highlighter





三月 14

讓RouterOS自動把Log檔Mail出去,這個動作可以拆成2個步驟來執行

1.在System->Script建立相關的Script(產生Log檔案,發送mail)

2.在System->Scheduler建立排程(判斷Log的行數到達我們的設定值就Mail出去)

第1個部份,先建立2個Script

建立一個名為MailLog的Script

請修改SMTP伺服器位置(記得ROS的DNS要有,才可以解析)、寄件人、收件人的資訊


#Script在RouterOS 3.20中測試通過
#Date:2009/03/14
#Script Name:MailLog

#SMTP伺服器位置
:local SMTP "xxx.smtp.com"

#寄件人
:local MailFrom "ROSLog<ROS@xxxxxxxxx.com>"

#收件人
:local MailTo "REC@xxxxxxxxx.com"

#Log檔的名稱(位於/file)
:local LogFileName

#寄出後是否刪除已存檔的Log(/file裡的檔案)
#0=保留  1=刪除
:local DeleteLogFile 1

:set LogFileName ([/system identity get name] . "Log-" . [:pick [/system clock get date] 7 11] . [:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6] . ".txt");

/tool e-mail set from=$MailFrom;

/log print file=[$LogFileName];

/tool e-mail send to=$MailTo server=[:resolve $SMTP] subject=([/system identity get name] . " Log " . [/system clock get date]) file=[$LogFileName];

:delay 10;

:if ($DeleteLogFile =1) do={
/file rem [/file find name=($LogFileName)];
}

:log info ("System Log emailed at " . [/sys cl get time] . " " . [/sys cl get date]);

接下來建立名為AutoMailLog的Script

超過幾條就把Log寄出去請依照你的實際需要設置

寄出後會自動清空Log,如果你想保留Log

那就把:local IsClearLog 1 改為:local IsClearLog 0

不過這樣子會造成每次都會寄發Mail,請特別注意


#Script在RouterOS 3.20中測試通過
#Date:2009/03/14
#Script Name:AutoMailLog

#超過幾條就把Log寄出去
:local MaxLine 300

#寄出後是否要清空現有的Log資訊
#0=保留  1=清空
:local IsClearLog 1

:if ([/log print count-only] >= $MaxLine) \
do={
/system script run MailLog;
:if ($IsClearLog = 1) \
do={/system script run ClearMemoryLog;}
}

第2個部份是建立Scheduler排程

在System->Scheduler 新增一個名為MailLog的排程

內容只有一行,時間是我是設定為5分鍾跑一次


/system script run AutoMailLog

最後總結一下,整個流程如下圖

參考資料:http://forum.mikrotik.com/viewtopic.php?f=9&t=29122





三月 13

如果我們想利用SSH,透過內網裡的某一台Linux主機

和內網的電腦連線,可以使用SSH Tunnel的方式來建立

情境圖如下

正常清況下我們是不能夠從外面直接連到圖中WindowsXP這台電腦的

要怎麼做才能連到內部的網路呢?一般來說常見的有2種作法

1.在Linux上面架設PPTP 、OpenVPN等服務

2.直接利用SSH的Tunnel來連線(前提是要有SSH這服務)

我是採用第2種方法來使用(方便又簡單)。這邊用PieTTY來做範例設定

實例:

如果我要使用WindowsXP這台電腦的遠端桌面,於SSH登入後

在設定Tunnel的頁面,Source port輸入999,Destination輸入192.168.1.210:3389

下面的2個選項就選用Local與Auto就行了

按下Add。然後在你的桌面開啟遠端連線,位置的部份就輸入127.0.0.1:999

接下來應該就連的上去了~~~

更多參考資料:

PuTTY - SSH Tunnel 運用備忘

使用SSH Tunnel從外網web來管理brazilfw(譯)





三月 12

RouterOS 在3.0版以後推出了API可以讓外部程式存取

這樣子功能性真的是延伸了很多

目前API支援以下幾種程式語言

in Perl - forum thread by cheesegrits
in Delphi - forum thread and wiki by rodolfo
in PHP - wiki link by Denis Basta
Java sample methods - forum post
in Python - wiki link by Mikrotik staff
in C# - wiki link by wiki user Gregy

可惜沒有VB.NET的版本。不過只要有C#的版本,一切就好辦事了

以下是轉換過後VB.NET版的API

不過傳送或讀取的值如果是中文的話會變成亂碼,這部份要再研究一下

使用前記得先開啟API的服務

/ip service enable api

或是利用圖型介面開啟 IP->Service

VB.NET版本的RouterOS API程式碼如下

Imports System.Net.Sockets
Imports System.IO
Imports System.Text

Class MK_ROS
    Private connection As Stream
    Private con As TcpClient

    Public Sub New(ByVal ip As String)
        con = New TcpClient()
        con.Connect(ip, 8728)
        connection = DirectCast(con.GetStream(), Stream)
    End Sub
    Public Sub Close()
        connection.Close()
        con.Close()
    End Sub
    Public Function Login(ByVal username As String, ByVal password As String) As Boolean
        Send("/login", True)
        Dim hash As String = Read()(0).Split(New String() {"ret="}, StringSplitOptions.None)(1)
        Send("/login")
        Send("=name=" & username)
        Send("=response=00" & EncodePassword(password, hash), True)
        If Read()(0) = "!done" Then
            Return True
        Else
            Return False
        End If
    End Function
    Public Sub Send(ByVal co As String)
        Dim bajty As Byte() = Encoding.ASCII.GetBytes(co.ToCharArray())
        Dim velikost As Byte() = EncodeLength(bajty.Length)

        connection.Write(velikost, 0, velikost.Length)
        connection.Write(bajty, 0, bajty.Length)
    End Sub
    Public Sub Send(ByVal co As String, ByVal endsentence As Boolean)
        Dim bajty As Byte() = Encoding.ASCII.GetBytes(co.ToCharArray())
        Dim velikost As Byte() = EncodeLength(bajty.Length)
        connection.Write(velikost, 0, velikost.Length)
        connection.Write(bajty, 0, bajty.Length)
        connection.WriteByte(0)
    End Sub
    Public Function Read() As List(Of String)
        Dim output As New List(Of String)()
        Dim o As String = ""
        Dim tmp As Byte() = New Byte(3) {}
        Dim count As Long
        While True
            tmp(3) = CByte(connection.ReadByte())
            'if(tmp[3] == 220) tmp[3] = (byte)connection.ReadByte(); it sometimes happend to me that
            'mikrotik send 220 as some kind of "bonus" between words, this fixed things, not sure about it though
            If tmp(3) = 0 Then
                output.Add(o)
                If o.Substring(0, 5) = "!done" Then
                    Exit While
                Else
                    o = ""
                    Continue While
                End If
            Else
                If tmp(3) < &H80 Then
                    count = tmp(3)
                Else
                    If tmp(3) < &HC0 Then
                        Dim tmpi As Integer = BitConverter.ToInt32(New Byte() {CByte(connection.ReadByte()), tmp(3), 0, 0}, 0)
                        count = tmpi Xor &H8000
                    Else
                        If tmp(3) < &HE0 Then
                            tmp(2) = CByte(connection.ReadByte())
                            Dim tmpi As Integer = BitConverter.ToInt32(New Byte() {CByte(connection.ReadByte()), tmp(2), tmp(3), 0}, 0)
                            count = tmpi Xor &HC00000
                        Else
                            If tmp(3) < &HF0 Then
                                tmp(2) = CByte(connection.ReadByte())
                                tmp(1) = CByte(connection.ReadByte())
                                Dim tmpi As Integer = BitConverter.ToInt32(New Byte() {CByte(connection.ReadByte()), tmp(1), tmp(2), tmp(3)}, 0)
                                count = tmpi Xor &HE0000000
                            Else
                                If tmp(3) = &HF0 Then
                                    tmp(3) = CByte(connection.ReadByte())
                                    tmp(2) = CByte(connection.ReadByte())
                                    tmp(1) = CByte(connection.ReadByte())
                                    tmp(0) = CByte(connection.ReadByte())
                                    count = BitConverter.ToInt32(tmp, 0)
                                Else
                                    'Error in packet reception, unknown length
                                    Exit While
                                End If
                            End If
                        End If
                    End If
                End If
            End If

            For i As Integer = 0 To count - 1
                o += ChrW(connection.ReadByte())
            Next
        End While
        Return output
    End Function
    Private Function EncodeLength(ByVal delka As Integer) As Byte()
        If delka < &H80 Then
            Dim tmp As Byte() = BitConverter.GetBytes(delka)
            Return New Byte(0) {tmp(0)}
        End If
        If delka < &H4000 Then
            Dim tmp As Byte() = BitConverter.GetBytes(delka Or &H8000)
            Return New Byte(1) {tmp(1), tmp(0)}
        End If
        If delka < &H200000 Then
            Dim tmp As Byte() = BitConverter.GetBytes(delka Or &HC00000)
            Return New Byte(2) {tmp(2), tmp(1), tmp(0)}
        End If
        If delka < &H10000000 Then
            Dim tmp As Byte() = BitConverter.GetBytes(delka Or &HE0000000)
            Return New Byte(3) {tmp(3), tmp(2), tmp(1), tmp(0)}
        Else
            Dim tmp As Byte() = BitConverter.GetBytes(delka)
            Return New Byte(4) {&HF0, tmp(3), tmp(2), tmp(1), tmp(0)}
        End If
    End Function

    Public Function EncodePassword(ByVal Password As String, ByVal hash As String) As String
        Dim hash_byte As Byte() = New Byte(hash.Length / 2 - 1) {}
        For i As Integer = 0 To hash.Length - 2 Step 2
            hash_byte(i / 2) = [Byte].Parse(hash.Substring(i, 2), System.Globalization.NumberStyles.HexNumber)
        Next
        Dim heslo As Byte() = New Byte(1 + Password.Length + (hash_byte.Length - 1)) {}
        heslo(0) = 0
        Encoding.ASCII.GetBytes(Password.ToCharArray()).CopyTo(heslo, 1)
        hash_byte.CopyTo(heslo, 1 + Password.Length)

        Dim hotovo As Byte()
        Dim md5 As System.Security.Cryptography.MD5

        md5 = New System.Security.Cryptography.MD5CryptoServiceProvider()

        hotovo = md5.ComputeHash(heslo)

        'Convert encoded bytes back to a 'readable' string
        Dim navrat As String = ""
        For Each h As Byte In hotovo
            navrat += h.ToString("x2")
        Next
        Return navrat
    End Function
End Class

使用方式如下

Dim mikrotik As New MK_ROS("主機位置(可為IP或Domain)")
If Not mikrotik.Login("帳號", "密碼") Then
    TextBox1.Text &= ("連線失敗")
    mikrotik.Close()
    Return
End If
'要下的指令
mikrotik.Send("/system/identity/print", True)
For Each h As String In mikrotik.Read()
    TextBox1.Text &= h
Next

參考資料:

Mikrotik RouterOS v3.x features

RouterOS API

RouterOS Community Support [Scripting]





三月 11

在Windows中如果覺得網路怪怪的

可以在控制台->網路連線->區域連線 按右鍵

然後選擇修復。這時候Windows會幫我們做一些網路修復的動作

如果我們想用指令(cmd)的方式取代圖型介面,該怎麼做呢?

Windows做的動作可以在微軟官方文件找到說明

微軟官方文件加上我的一點語意修正後:

* 更新 DHCP:ipconfig /renew
* 清除ARP快取:arp -d *
* 重新載入 NetBIOS 快取:nbtstat -R
* 更新 NetBIOS 名稱:nbtstat -RR
* 清除 DNS 快取:ipconfig /flushdns
* DNS 名稱登錄:ipconfig /registerdns

你也可以把以下指令存成批次檔(Repair.bat)執行


@echo off
echo "更新 DHCP"
ipconfig /renew
echo "------------------------------"
echo "清除ARP快取"
arp -d *
echo "------------------------------"
echo "重新載入 NetBIOS 快取"
nbtstat -R
echo "------------------------------"
echo "更新 NetBIOS 名稱"
nbtstat -RR
echo "------------------------------"
echo "清除 DNS 快取"
ipconfig /flushdns
echo "------------------------------"
echo "DNS 名稱登錄"
ipconfig /registerdns
echo "------------------------------"

參考資料:區域網路或高速網際網路連線的修複選項說明