2014年3月13日 星期四

DD-WRT DualWAN FailOver Scripts

Dual WAN With Failover

This was tested on WRT54GL 1.1 with DD-WRT 2.4 mini.

Contents



What this setup will do

Create a second WAN port, so you can hook up another provider for backup, and will change the active provider to the secondary, if ping fails to the provider's gateway. It will ping in a predefined interval. If this is not what you need, then you might try:


Creating a second VLAN

You'll need to create a new VLAN, called vlan2. Enter in the web interface, Settings/VLANs. Set Port 4 to a new VLAN. Enter in the console, and do the following commands


Commands to set VLANs

nvram set vlan0ports="1 2 3 5*"
nvram set vlan2ports="0 5"
nvram set vlan2hwname=et0
nvram commit
On a WRT54GL this will be port 4, if you want port 1 for vlan2 then set vlan2ports to "3 5".


Setting up the scripts

We'll have some scripts, which will go in /jffs/etc/config.


Bringing up the second WAN at startup



wan2up.startup

Now this is for static IP, but you can change this situation by modifying the script for udhcpc
#!/bin/sh
WAN2_IFNAME=vlan2
WAN2_IPADDR=192.168.2.2
WAN2_GATEWAY=192.168.2.1
WAN2_NETMASK=255.255.255.0
if [ "$(nvram get wan2_ipaddr)" != "$WAN2_IPADDR" ]; then
        nvram set wan2_ifname=$WAN2_IFNAME   
   nvram set wan2_ipaddr=$WAN2_IPADDR
   nvram set wan2_gateway=$WAN2_GATEWAY
   nvram set wan2_netmask=$WAN2_NETMASK
   nvram commit
fi
ifconfig $(nvram get wan2_ifname) up $(nvram get wan2_ipaddr) netmask $(nvram get wan2_netmask)
# We will want to set masquerade on WAN2, otherwise after changing active WAN, we'll remain up in the air.
iptables -t nat -A POSTROUTING -o vlan2 -j MASQUERADE


Setting up the scripts responsible for switching to a specific WAN

This file makes the changes necessary to activate WAN1. Change the nameservers to your provider's DNS servers or OpenDNS's.


wan1.up

#!/bin/sh
# WAN1 
DEV=vlan1
GATEWAY=`nvram get wan_gateway` 
DNS1=193.226.43.33
DNS2=193.230.175.1

nvram set wan_dns="$DNS1 $DNS2"
ip route delete default
# ip route delete default
ip route add default via $GATEWAY dev $DEV
echo "nameserver $DNS1" >/tmp/resolv.dnsmasq
echo "nameserver $DNS2" >>/tmp/resolv.dnsmasq
pr="$(ps|awk '/dnsmasq/ {print $1}')"
kill -9 $pr
dnsmasq --conf-file=/tmp/dnsmasq.conf
As you probably already figured out, this will make the changes necessary to activate WAN2 :)


wan2.up

#!/bin/sh
# WAN2 
DEV=vlan2
GATEWAY=`nvram get wan2_gateway` 
DNS1=193.226.43.33
DNS2=193.230.175.1

nvram set wan_dns="$DNS1 $DNS2"
ip route delete default
# ip route delete default
ip route add default via $GATEWAY dev $DEV
echo "nameserver $DNS1" >/tmp/resolv.dnsmasq
echo "nameserver $DNS2" >>/tmp/resolv.dnsmasq
pr="$(ps|awk '/dnsmasq/ {print $1}')"
kill -9 $pr
dnsmasq --conf-file=/tmp/dnsmasq.conf


Setting up the actual failover script

Now, this is the core of our goal, this script will monitor the active connection, and if connection fails, it will call one of wan1.up or wan2.up to change the active connection.


failover.startup

#!/bin/sh
INTERVAL=10
PACKETS=1
USINGWAN=0
WAN1=vlan1
WAN2=vlan2
WAN1GW=`nvram get wan_gateway`
WAN2GW=`nvram get wan2_gateway`

# We'll run this in the intervals given above
while sleep $INTERVAL
do
        # Try to figure out the current route
        TARGET=`ip route | awk '/default via/ {print $3}'`
        # Set the variable, so let the script now which connection is it dealing with
        if [ "$WAN1GW" = "$TARGET" ]; then 
                USINGWAN=1;
        else if [ "$WAN2GW" = "$TARGET" ]; then
                USINGWAN=2;
          fi;
        fi
        # We'll ping as many times the $PACKETS variable tells, and test if we have connection:
        RET=`ping -c $PACKETS $TARGET 2>/dev/null | awk '/packets received/ {print $4}'`
        # If we don't have connection, change the active WAN port (If there is any loss with multiple packets, it should change either)
        if [ "$RET" -ne "$PACKETS" ]; then
                if [ "$USINGWAN" = "1" ]; then
                        /jffs/etc/config/wan2.up
                        USINGWAN=2
                        echo "Changed active WAN port to 2!"
                else
                        /jffs/etc/config/wan1.up
                        USINGWAN=1
                        echo "Changed active WAN port to 2!"
                fi
        fi 
done;


Optionally add automatic switching back to WAN1 once it becomes available

When WAN2 is in use as the active WAN port the script will check the status of WAN1 at the regular interval and switch back to it when it becomes available. Useful if WAN2 is a slower or paid-use connection.
Add these lines to failover.startup just before the last line (done;).
if [ "$USINGWAN" = "2" ]; then
WAN1STAT=`ping -c $PACKETS $WAN1GW 2>/dev/null | awk '/packets received/ {print $4}'`
if [ "$WAN1STAT" = "$PACKETS" ]; then
/jffs/etc/wan1.up
USINGWAN=1
echo "Changed active WAN port to 1!"
fi
fi


Setting up the script responsible for the Easy Setup button

Optionally, if you want to be able to switch the active WAN port with the Easy Setup button, you can add:


chwan.sesbutton

#!/bin/sh
USINGWAN=0
WAN1=vlan1
WAN2=vlan2
WAN1GW=`nvram get wan_gateway`
WAN2GW=`nvram get wan2_gateway`

        TARGET=`ip route | awk '/default via/ {print $3}'`
        if [ "$WAN1GW" = "$TARGET" ]; then 
                USINGWAN=1;
        else if [ "$WAN2GW" = "$TARGET" ]; then
                USINGWAN=2;
          fi;
        fi
ip route delete default
if [ "$USINGWAN" = "1" ]; then
        /jffs/etc/config/wan2.up
        USINGWAN=2
        echo "Changed active WAN port to 2!"
        else
        /jffs/etc/config/wan1.up
        USINGWAN=1
        echo "Changed active WAN port to 1!"
fi


Final polishing

Create above files in /jffs/etc/config and then do a
chmod +x /jffs/etc/config/*
If you made everything as written above right, you should reboot the router and enjoy!

2014年2月26日 星期三

IPC(socket)

from:http://jimmychenhaha.blogspot.tw/2012/12/ipcsocket.html

網路找到的範例: 很不錯

http://www.cs.cf.ac.uk/Dave/C/node28.html

source code:
https://docs.google.com/folder/d/0B8hm-I2M8BD7TkVJcGtHQUM3MTg/edit

server.c 


#include
#include
#include
#include

#define NSTRS       3           /* no. of strings  */
#define ADDRESS     "mysocket"  /* addr to connect */

/*
 * Strings we send to the client.
 */
char *strs[NSTRS] = {
    "This is the first string from the server.\n",
    "This is the second string from the server.\n",
    "This is the third string from the server.\n"
};

main()
{
    char c;
    FILE *fp;
    int fromlen;
    register int i, s, ns, len;
    struct sockaddr_un saun, fsaun;

    /*
     * Get a socket to work with.  This socket will
     * be in the UNIX domain, and will be a
     * stream socket.
     */
    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("server: socket");
        exit(1);
    }

    /*
     * Create the address we will be binding to.
     */
    saun.sun_family = AF_UNIX;
    strcpy(saun.sun_path, ADDRESS);

    /*
     * Try to bind the address to the socket.  We
     * unlink the name first so that the bind won't
     * fail.
     *
     * The third argument indicates the "length" of
     * the structure, not just the length of the
     * socket name.
     */
    unlink(ADDRESS);
    len = sizeof(saun.sun_family) + strlen(saun.sun_path);

    if (bind(s, &saun, len) < 0) {
        perror("server: bind");
        exit(1);
    }

    /*
     * Listen on the socket.
     */
    if (listen(s, 5) < 0) {
        perror("server: listen");
        exit(1);
    }

    /*
     * Accept connections.  When we accept one, ns
     * will be connected to the client.  fsaun will
     * contain the address of the client.
     */
    if ((ns = accept(s, &fsaun, &fromlen)) < 0) {
        perror("server: accept");
        exit(1);
    }

    /*
     * We'll use stdio for reading the socket.
     */
    fp = fdopen(ns, "r");

    /*
     * First we send some strings to the client.
     */
    for (i = 0; i < NSTRS; i++)
        send(ns, strs[i], strlen(strs[i]), 0);

    /*
     * Then we read some strings from the client and
     * print them out.
     */
    for (i = 0; i < NSTRS; i++) {
        while ((c = fgetc(fp)) != EOF) {
            putchar(c);

            if (c == '\n')
                break;
        }
    }

    /*
     * We can simply use close() to terminate the
     * connection, since we're done with both sides.
     */
    close(s);

    exit(0);
}



client.c

#include
#include
#include
#include

#define NSTRS       3           /* no. of strings  */
#define ADDRESS     "mysocket"  /* addr to connect */

/*
 * Strings we send to the server.
 */
char *strs[NSTRS] = {
    "This is the first string from the client.\n",
    "This is the second string from the client.\n",
    "This is the third string from the client.\n"
};

main()
{
    char c;
    FILE *fp;
    register int i, s, len;
    struct sockaddr_un saun;

    /*
     * Get a socket to work with.  This socket will
     * be in the UNIX domain, and will be a
     * stream socket.
     */
    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("client: socket");
        exit(1);
    }

    /*
     * Create the address we will be connecting to.
     */
    saun.sun_family = AF_UNIX;
    strcpy(saun.sun_path, ADDRESS);

    /*
     * Try to connect to the address.  For this to
     * succeed, the server must already have bound
     * this address, and must have issued a listen()
     * request.
     *
     * The third argument indicates the "length" of
     * the structure, not just the length of the
     * socket name.
     */
    len = sizeof(saun.sun_family) + strlen(saun.sun_path);

    if (connect(s, &saun, len) < 0) {
        perror("client: connect");
        exit(1);
    }

    /*
     * We'll use stdio for reading
     * the socket.
     */
    fp = fdopen(s, "r");

    /*
     * First we read some strings from the server
     * and print them out.
     */
    for (i = 0; i < NSTRS; i++) {
        while ((c = fgetc(fp)) != EOF) {
            putchar(c);

            if (c == '\n')
                break;
        }
    }

    /*
     * Now we send some strings to the server.
     */
    for (i = 0; i < NSTRS; i++)
        send(s, strs[i], strlen(strs[i]), 0);

    /*
     * We can simply use close() to terminate the
     * connection, since we're done with both sides.
     */
    close(s);

    exit(0);
}

IPC (share memory)

From:http://jimmychenhaha.blogspot.tw/2012/10/ipcshare-memory.html

[Function]

#include
int shmget(key_t key, size_t size, int shmflg);

key:
      IPC_PRIVATE:產生一個新的共享記憶體分段

size:
      需要共享記憶體的大小 , 因為分配大小皆以page為單位 , 所以如果size = 1~4096 , 則實際上會分配到4k.

shmflag:
      S_IRUSR: 讀記憶體分段
      S_IWUSR: 寫記憶體分段
      IPC_CREAT :確保開啟的記憶體是新的,而不是現存的記憶體.
      | 0666 : 作為校驗 ,  ubuntu要加

<shmat>
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:
          共享記憶體的id

shmaddr:
     NULL:讓系統自己選擇.

shmflg:
     SHM_RDONLY:唯讀模式
          0:可讀可寫

<shmdt>          

#include
int shmdt(const void *shmaddr);
<shmctl>
 #include
#include
 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:
           share memory id
cmd:
          IPC_STAT: 從共享記憶體裡,拿 shmid_ds 結構資料給 buf.
          IPC_SET: 從buf 複製到共享記憶體
          IPC_RMID: 砍了共享記憶體
buf:
        就暫存區.

[CODE] 


#include
#include
#include
#include
#include
#define shm_size     32
#define PARM IPC_CREAT | 0666
int main(void)
{
    char c;
    int shm_id;
    char *shm_addr, *s;
 key_t key;

 key = 5679;
    if ((shm_id = shmget(key, shm_size, PARM)) < 0) {
        perror("shmget");
        return 0;
    }
    if ((shm_addr = shmat(shm_id, NULL, 0)) == (char *) -1) {
        perror("shmat");
        return 1;
    }
    s = shm_addr;
    for (c = 'a'; c <= 'z'; c++)
        *s++ = c;
    *s = NULL;

    while (*shm_addr != '*'){
        sleep(1);
 }

 shmdt(shm_addr);
 shmctl(shm_id , IPC_RMID , NULL);
    return 0;
}

#include
#include
#include
#include
#include
#define shm_size     32
int main(void)
{
    int shmid;
    key_t key;
    char *shm, *s;
    key = 5679;
    if ((shmid = shmget(key, shm_size , S_IRUSR | 0666)) < 0) {
        perror("shmget");
        return 1;
    }
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        return 1;
    }
    for (s = shm; *s != NULL; s++)
        putchar(*s);
    putchar('\n');
    *shm = '*';

 return 0;
}


[編譯]
gcc -o server shm_server.c
gcc -o client shm_client.c
./server &
./client &

最後顯示
 haha@haha-VirtualBox:~/work$ abcdefghijklmnopqrstuvwxyz


ref:http://systw.net/note/af/sblog/more.php?reply=ok&id=235&tl=no

2014年2月18日 星期二

JSON (JavaScript Object Notation) Format

完整的JSON寫法:

01{
02  'familys' = [
03    {'name' 'Bruce',
04     'age' : 18,
05     'sex' 'male'},
06    {'name' 'Sherry',
07     'age' : 16,
08     'sex' 'famale'}
09  ]
10}

JSON會建構出兩種結構:(1)「"名稱" : 值」的集合;(2)Array。

JSON的細節

比對上面範例,你會發現一點也不難。

JSON Object:
  1. 以"{"開始,以"}"結尾
  2. 每個名稱後跟著一個":"
  3. 每對"名稱:值"之間用","分隔
1// 以"{"開始
2  'name' 'Bruce',  // 每個名稱後跟著一個":"
3  'age' : 18,        // 每對"名稱:值"之間用","分隔
4  'sex' 'male'
5// 以"}"結尾

JSON Array:
  1. 以"["開始,以"]"結尾
  2. 值之間使用","
01{
02  // familys為一維陣列,陣列裡包含兩筆物件資料
03  'familys' = [  // 以"["開始
04    {'name' 'Bruce',
05     'age' : 18,
06     'sex' 'male'},  // 值之間使用","
07    {'name' 'Sherry',
08     'age' : 16,
09     'sex' 'famale'}
10  // 以"]"結尾
11}

JSON Value:
  • 值本身可以是String、Number、true、false、null、ObjectArray

JSON String:
  • 由雙引號包圍的任意Unicode字元集合。可以使用"反斜線(\)"來轉義。
1{
2  "details" "這是JSON的值. \n 此格式比XML合適Ajax交換資料使用."
3}

JSON Number:
  • 與一般數值相同,除8 / 16進制外。

How to repair and clone disk with ddrescue

  ddrescue  is a tool that can be used to repair and clone disks on a  Linux system . This includes hard drives, partitions, DVD discs, flas...