2008/12/18

VIM is so cool

VIM is really cool, you can increase/decrease a number in the text directly by with CTRL-A and CTRL-X!


Adding and subtracting

*CTRL-A*
CTRL-A Add [count] to the number or alphabetic character at
or after the cursor. {not in Vi}


*CTRL-X*
CTRL-X Subtract [count] from the number or alphabetic
character at or after the cursor. {not in Vi}

The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned
octal and hexadecimal numbers and alphabetic characters. This depends on the
'nrformats' option.
- When 'nrformats' includes "alpha", Vim will change the alphabetic character
under or after the cursor. This is useful to make lists with an alphabetic
index.
- When 'nrformats' includes "hex", Vim assumes numbers starting with '0x' or
'0X' are hexadecimal. The case of the rightmost letter in the number
determines the case of the resulting hexadecimal number. If there is no
letter in the current number, Vim uses the previously detected case.
- When 'nrformats' includes "octal", Vim considers numbers starting with a '0'
to be octal. Other numbers are decimal and may have a preceding minus sign.
If the cursor is on a number, the commands apply to that number; otherwise
Vim uses the number to the right of the cursor.

For numbers with leading zeros (including all octal and hexadecimal numbers),
Vim preserves the number of characters in the number when possible. CTRL-A on
"0077" results in "0100", CTRL-X on "0x100" results in "0x0ff". Note that
when 'nrformats' includes "octal", decimal numbers with leading zeros are
impossible because they are indistinguishable from octal numbers.

The CTRL-A command is very useful in a macro. Example: Use the following
steps to make a numbered list.

1. Create the first list entry, make sure it starts with a number.
2. qa - start recording into buffer 'a'
3. Y - yank the entry
4. p - put a copy of the entry below the first one
5. CTRL-A - increment the number
6. q - stop recording
7. @a - repeat the yank, put and increment times

2008/12/11

Mapping remote TCP port to local via HTTPS Proxy

上次说的Perl代码供大家参考

功能:把远端的应用服务端口通过HTTPS代理服务器映射成本地端口。这对于那些不支持HTTPS代理的TCP应用还有点儿小用处! :D


#!/usr/bin/env perl
#
# Use remote HTTPS PROXY to tunnel the remote service to local!
# Author: Yi Zhao
#   Blog: linuxyz.blogspot.com
#
# Based on original "ssltunnel.pl" by Alex Hornby <alex@hornby.org.uk>
# $Id: ssltunnel.pl,v 1.17 2003/06/10 14:54:16 alex Exp $
#
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#

package httpsproxy;

use strict;
my $VERSION=1.0;

use IO::File;
use IO::Select;
use IO::Socket;
use Net::SSL;
use Getopt::Long;
use MIME::Base64;

my %options = (
    proxyport=>443,
    reproxyport=>8080,
    localaddr=>"127.0.0.1",
    localport=>8080,
);

sub usage
{
    print STDERR <<EOF;
usage: perl httpsproxy.pl [options] [remote-host:port]
Tunnels a TCP/IP connection through an http proxy using SSL.

WARNING: Only use this if you have the proxy administrator\'s permission
WARNING: The authors of this package offer no warranty

options:
    --help                        This help
    --proxyhost 1.2.3.4           Mandatory proxy host port (default 443)
    --proxyport 443               Optional proxy host port (default 443)
    --proxyuser <username>        Optional proxy user name
    --proxypasswd pass            Optional proxy pass word
    --useragent agent             Optional user agent name
    --reproxyhost 1.2.3.4         Optional intermediate http proxy host
    --reproxyport 123             Optional intermediate http proxy host port (default 8080)
    --reproxyuser <username>      Optional intermediate http proxy user name
    --reproxypasswd pass          Optional intermediate http proxy pass word
    --localaddr 1.2.3.4           Optional local addr to listen on (default 127.0.0.1)
    --localport 123               Optional local port to listen on (default 8080)

e.g. To run a local http proxy to the remote HTTPS proxy

./httpsproxy.pl --proxyhost 10.1.1.80 \
  --proxyport 443 --localport 80  www.abc.com:80

EOF
    exit(1);
}

# Parse command line arguments
sub parseArgs
{
    GetOptions(\%options, qw/dumpfile=s
                   proxyhost=s proxyport=i proxyuser=s proxypasswd=s useragent=s
                   reproxyhost=s reproxyport=i reproxyuser=s reproxypasswd=s reuseragent=s
                   localaddr=s localport=i
                   debug! help!
                   log-file=s pidfile=s/);

    if ( $options{help} ) {
        usage();
    }

    for (@ARGV) {
        if (m/^([^:]*):(.*)$/) {
            $options{desthost} = $1;
            $options{destport} = int($2) || getservbyname($2, 'tcp') || die "unknown port";
            print "Mapping $options{desthost}:$options{destport} as $options{localaddr}:$options{localport}\n";
        }
    }
    
    if ( !defined($options{proxyhost}) ) {
        print STDERR "error: You must give a proxyhost\n";
        usage();
    }
}

# This is really inefficient, but we only use it for reading the proxy response
# so that does not really matter.
sub xgetline($)
{
    my $proxy = shift;
    my $val="";
    my $buf;
    do {
        $proxy->read($buf, 1);
        $val .= $buf;
    } until ($buf eq "\n");

    $val;
}

sub httpProxy
{
    my ( $proxy, $desthost, $destport, $proxyuser, $proxypasswd ) = @_;
    # Force flushing of socket buffers

    # The actual connect
    $proxy->print("CONNECT " .  $desthost . ":" .
                      $destport . " HTTP/1.0\r\n");
    if ( $options{debug} ) {
        print STDERR "CONNECT " .  $desthost . ":" .
                      $destport . " HTTP/1.0\n";
    }

    # Basic auth if needed
    if ( $proxyuser ) {
        my $auth = encode_base64(
            $proxyuser . ":" . $proxypasswd);
        $proxy->print("Proxy-authorization: Basic $auth\r\n");
        if ( $options{debug} ) {
            print STDERR "Proxy-authorization: Basic $auth"
        }
    }

    # User agent name if needed
    if ( $options{useragent} ) {
        $proxy->print("User-Agent: " . $options{useragent} . "\r\n");
        if ( $options{debug} ) {
            print STDERR "User-Agent: " . $options{useragent} . "\n";
        }
    }

    # end of headers
    $proxy->print("\r\n");

    my $status;

    # Wait for HTTP status code, bail out if you don't get back a 2xx code.
    #$_ = $proxy->getline();
    #$_ = $proxy->getchunk();
    $_ = xgetline($proxy);
    next if /^[\r]*$/;
    ($status) = (split())[1];
    die("Received a bad status code \"$status\" from proxy server\n$_")
        if ( int($status/100) != 2 );

    while($_ = xgetline($proxy)) {
        chomp;   # Strip <LF>
        last if /^[\r]*$/;                # Empty line or a single <CR> left

        if ( $options{debug} ) {
            print STDERR "Got extra data [$_]\n";
        }
    }

    return $status;
}

sub connectProxy
{
    if ( $options{reproxyhost} ) {
        # proxy support
        $ENV{HTTPS_PROXY} = qq(http://$options{reproxyhost}:$options{reproxyport});

        # proxy_basic_auth
        $ENV{HTTPS_PROXY_USERNAME} = $options{reproxyuser} if $options{reproxyuser};
        $ENV{HTTPS_PROXY_PASSWORD} = $options{reproxypass} if $options{reproxypass};
    }

    # debugging (SSL diagnostics)
    $ENV{HTTPS_DEBUG} = $options{debug} ? 1 : 0;
  
    my $proxy = new Net::SSL (
        PeerAddr => $options{proxyhost},
        PeerPort => $options{proxyport},
        Proto => 'tcp',
    );

    die "Error connecting to proxy host $options{proxyhost} " .
        "port $options{proxyport}: $!\n" unless $proxy;

    # Force flushing of socket buffers
    $proxy->autoflush(1);

    # only if the remote host are speficied
    httpProxy($proxy, $options{desthost}, $options{destport},
        $options{proxyuser}, $options{proxypasswd} )
    if ( $options{desthost} );

    return $proxy;
}

sub connectLocal
{
    my $listen = new IO::Socket::INET (
        Listen=> 5,
        LocalAddr => $options{localaddr},
        LocalPort => $options{localport},
        Proto => 'tcp',
        Reuse => 1,
    );

    die "can't listen on " . $options{localaddr} . ":"
        . $options{localport} unless $listen;

    print STDERR "Accepting network clients on " .
        $options{localaddr} . ":" .$options{localport} . "\n";

    my %client2proxy;
    my %proxy2client;

    my $s = IO::Select->new();
    $s->add($listen);

    my $dumpfh;
    if ( $options{dumpfile} ) {
        $dumpfh = new IO::File($options{dumpfile}, "w")
            or die "could not open dump file $_";
        $dumpfh->autoflush(1);
    }

    while ( 1 ) {
        my @res = IO::Select::select($s, undef, undef, 3600);
        if ( @res == 0 ) {
            print STDERR "got select error\n";
            last;
        }
        my ($read, $write, $error) = @res;

        # Check for disconnect
        for my $fh ( @$error ) {
            print STDERR "socket $fh is in error\n";
            $s->remove($fh);
            exit();
        }

        # Process handles ready to read;
        for my $fh ( @$read  ) {

            if ( $fh == $listen ) {
                my $client = $listen->accept();
                $client->autoflush(1);
                $s->add($client);
                my $proxy = connectProxy();
                $s->add($proxy);
                print STDERR "New connection from " . $client->peerhost() . "\n";
                $client2proxy{$client} = $proxy;
                $proxy2client{$proxy} = $client;
            } else {
                my $destfh;
                my $isclient = 0;
                if ( exists( $client2proxy{$fh} ) ) {
                    $destfh = $client2proxy{$fh};
                    $isclient = 1;
                } elsif ( exists( $proxy2client{$fh} ) ) {
                    $destfh = $proxy2client{$fh};
                }

                my $num = sysread($fh, $_, 4096);
                if ( $num) {
                    syswrite($destfh, $_, $num);
                    # Optional dump of traffic
                    if ( $dumpfh ) {
                        if ($isclient) {
                            $dumpfh->print("client[$_]\n");
                        } else {
                            $dumpfh->print("proxy[$_]\n");
                        }
                    }
                } else {
                    $s->remove($fh);
                    $s->remove($destfh);
                    if ( $isclient ) {
                        print STDERR "client disconnected\n";
                        delete($client2proxy{$fh});
                        delete($proxy2client{$destfh});
                    } else {
                        print STDERR "proxy disconnected\n";
                        delete($client2proxy{$destfh});
                        delete($proxy2client{$fh});
                    }
                    close($fh);
                    close($destfh);

                    if(%proxy2client == 0 ) {
                        print STDERR "last client disconnected\n";
                    }
                }
            }
        }
    }
}

parseArgs();
connectLocal();

0;

__END__

copy and paste in VIM

VIM have multiple clipboard which allows you copy and save different content at the same time. The register can be any of {a-zA-Z0-9.%#:-"}. It is really interesting thing which I never notice before.

"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank
or put (use uppercase character to append with
delete and yank) ({.%#:} only work with put).

:reg[isters] Display the contents of all numbered and named
registers. {not in Vi}

:reg[isters] {arg} Display the contents of the numbered and named
registers that are mentioned in {arg}. For example:

["x]y{motion} Yank {motion} text [into register x]. When no
characters are to be yanked (e.g., "y0" in column 1),
this is an error when 'cpoptions' includes the 'E'
flag.

["x]p Put the text [from register x] after the cursor
[count] times. {Vi: no count}


I forgot there is another register *, it is as same as the system clipboard. So you can yank some text into register *, it will be in the system clipboard also. :D

2008/12/04

Apache HTTPD as Proxy server

由于条件限制,平时网络只能用http代理,其他任何应用都必须通过这个代理。可是这个代理只能支持http以及https应用,不支持CONNECT remote-host:443以外的其他端口,除了浏览网页根本不能用于其它代理。
为此,用Apache自建了一个HTTPS代理,这样就能够利用这个二次代理做一些其他的应用。

Apache HTTPD 真是强悍啊!首先在 httpd.conf 打开mod_proxy;
然后添加下面的语句:


ProxyRequests On
ProxyVia On

Order deny,allow
Deny from all
Allow from .mydomain.com



赶紧试验一下SSH! TLS握手都完成了,貌似就应该能工作了不?

可是实际上不行!:(

每次用 CONNECT 方法来连接服务器的时候总是被403踢下来。感觉应该是访问控制的问题,于是改成没有访问控制;再试过一样403 Forbidden~~~~ 郁闷啊!

看了半天Apache的文档才发现,原来还有一个 AllowCONNECT 指令,并且缺省只打开443和563端口,难怪连22 端口的时候被踢~~~~~

赶紧加上这句:
AllowCONNECT 21 22 23 80 443
再试,Working... 高喊:“Apache 太强悍了~~~”

题外话:这个二次代理的转换程序是用Perl写的,目前还有些小问题,啥时候时候搞好了也放上来!

BlockChain 相关电子书

@copyright of Sam Chadwick   - https://thehub.thomsonreuters.com/groups/bitcoin/blog/2017/09/10/blockchain-paper Blockchain Papers A c...