堆代码 – 折腾(存档) https://blog.sorz.org 已停止更新和维护。该页面为2018年3月创建的存档,其内容可能已过于陈旧、与现状不符,仅作为历史存档用作参考。 Sun, 14 Jan 2018 11:08:20 +0000 zh-CN hourly 1 https://wordpress.org/?v=4.9.4 简单的 BT Tracker 连接检测 /p/bt-tracker-helper/ /p/bt-tracker-helper/#respond Sat, 24 Oct 2015 09:43:43 +0000 /?p=348077

RT @kgen: 大家 BT 下载的时候,不要开着 VPN,发达国家的版权投诉猛如虎。版权方会主动放出一些正版的 BT 种子,然后收集所有连接来源 IP,投诉或索赔。

这对于 VPN 提供商来说也是一个很头疼的问题。现在的 BT 客户端为了避免被封,已经经进化出了各种加密、混淆手段,直接检测 P2P 流量很困难。不过,大多数时候,客户端都在下载是都会同时连接一些 BitTorrent tracker 服务器。这些服务器数量有限且地址、端口号相对固定,可以非常容易地收集,并直接通过 IP 地址和端口号判断而不必对流量内容进行深度检测。探测到了就扔炸弹。是一个简单易行的判断用户是否正在使用 BT 的方法。

这个方法已在某家梯子站上部署了有一段时间了。鉴于它误报率(false postive rate)低但漏报率(false negtive rate)高,检测到的「处罚」会比较严厉——发现连接就立即挂断这条 VPN 连接。效果似乎还不错,仅有的几次投诉经过排查,发现都是在这套机制的某些环节失效时发生的。

当时为了方便操作,写了几个脚本。现在重新整理了一下,放在了 GitHub 上。这个脚本主要用于从 BT 种子文件里收集 trackers 的地址,然后解析域名得到对应的 IP 地址、协议和端口号。脚本本身并不进行检测等操作,只是为了方便配置防火墙而写。

示例

先在各处收集一些 BT 种子,这些种子文件中通常会包含一个或多个的 trackers。可使用./trackers.py torrent获得 trackers 的 URL 列表,重复的地址会被自动剔除:

$ ./trackers.py torrent *.torrent > trackers.txt

$ cat trackers.txt
> http://tracker.yify-torrents.com
> udp://tracker.justseed.it:1337
> udp://tracker.openbittorrent.com:80
> http://nyaatorrents.info:3277
  ......

防火墙通常需要匹配 IP 地址而非域名,并且一个域名可能对应多个 IP。这个脚本提供了解析 tracker URL 的功能,每个地址会被解析为一个或多个 IP 地址 – 协议 – 端口 的组合:

$ ./trackers.py raw trackers.txt
> 188.166.82.104 tcp 6881
> 94.23.217.90 udp 1337
> 179.43.146.110 udp 80
  ......

使用 ipset 来匹配这些连接是一个不错的选择。可以使用./trackers.py ipset直接生成 ipset 规则,这些规则可经由ipset restore导入系统:

$ ./trackers.py ipset trackers trackers.txt > ipset.rules

$ cat ipset.rules
> create -exist trackers hash:ip,port family inet
> add -exist trackers 188.166.82.104,tcp:6881
> add -exist trackers 94.23.217.90,udp:1337
> add -exist trackers 179.43.146.110,udp:80
> ...

# ipset restore -file ipset.rules

另外,虽然不是很推荐这么做,从收集 trackers 到导入 ipset 的操作也可以一步完成:

# ./trackers.py torrent *.torrent | ./trackers.py ipset trackers - | ipset restore

导入 ipset 后,可以使用 iptables 匹配这个 ipset,进行进一步操作。例如可使用iptables -j LOG记录下连接 trackers 的行为:

# iptables -N TRACKERS
# iptables -A FORWARD -m set --match-set trackers dst,dst -j TRACKERS
# iptables -A TRACKERS -m limit --limit 1/sec --limit-burst 10 \
  -j LOG --log-level info --log-prefix trackers
# iptables -A TRACKERS -j DROP

一些发行版本使用了 syslogd 管理日志,可以修改它的配置,将连接记录转发至其他程序进行进一步处理。例如文章开头所说的,通过日志中记录的源 IP 识别出对应的用户,然后将其断线。

]]>
/p/bt-tracker-helper/feed/ 0
重构 ASS to SRT 字幕转换工具 /p/asstosrt/ /p/asstosrt/#comments Sat, 22 Feb 2014 14:22:27 +0000 https://sorz.org/?p=347827 重写了一遍两年前初学蛇语时写的字幕转换工具(ASS 字幕批量转 SRT)。

当时因常用某三星电视看动画,有这个需求。此外还想学下 Python,于是挖了这个坑..
自从最近把 VPS 邮件转发至 Gmail 后,不断被此坑在线版的错误报告骚扰,一翻代码,太羞耻了简直丑陋,决定换掉…

原有的功能都还在:批量、繁简转换、删特效字幕、仅保留首行、重排序、识别/指定编码。字幕重排序由可选改为强制启用。默认输出编码由 UTF-16 改为与源文件相同。兼容 Python 2.7 / 3.x。
不自带chardetlangconv这两个可选依赖了。后者为繁简转换所需,不在 PyPI 上,可在此处下载

非发烧用户请直接戳 在线版 就好了。
虽然网页还是旧的,内部已经换上了全新的 asstosrt。

Python 用户请直接:

pip install chardet
pip install asstosrt
asstosrt --help
]]>
/p/asstosrt/feed/ 9
利用上网卡转发短信至邮箱,来电提醒 /p/sms2email/ /p/sms2email/#comments Tue, 18 Jun 2013 14:11:04 +0000 http://sorz.org/?p=347689 想法
SMS to Email 效果

SMS to Email 效果

唔,最早的想法是:学校离家较远所以有两张SIM卡,而且由于资费原因只能分别在两地使用,想通过互联网代理,使得可以在一地同时使用两张卡..

最早想到的是使用闲置低端安卓机,后来发现手头闲置的一张华为数据卡(EC1261)可以利用,遂试着捣鼓出一个这玩意..

本文实现:

  • 将所收短信转发至指定 E-mail
  • 挂断来电并回复短信,同时发送 E-mail 提醒

虽然还不能接打电话,但至少接收各种验证短信不再麻烦了呢 🙂

设备

闲置 华为数据卡 EC1261 一张
装 ubuntu 的 Cubieboard 一块

这张上网卡除了上网,收发短信也是可以的:流量提醒就是用短信实现的(所以总是一条条地接收);带了个 2.5mm 耳机插口,应该是用来打电话的,虽然电信给的软件不带此功能。

其他型号的华为上网卡应该类似

安装

Windows: 插入装好驱动就成,华为上网卡用串口和 PC 通讯,插入后设备管理器中可见串口号(COMXX)。

Linux: 以前在 ubuntu 10.10 试过插上就能用。在刷了官网上下的 ubuntu 镜像的 Cubieboard 上,貌似装了 usb_modeswitch 才正常。若自行编译内核,需确保勾选usb_wwanoption模块。会看见类似/dev/ttyUSB0的设备出现。

脚本设计运行于 Linux,依赖 Python 2 和 pySerial,发邮件需装 sendmail 。

apt-get install python-serial sendmail usb-modeswitch

通讯

关于如何“操作”上网卡,这个是关键呢,感谢这篇文章给了我线索,搜索关键词 HUAWEI CDMA Datacard Modem AT Command Interface Specification 即可,PDF 里有详细说明。

根据说明写了段程序,完成标题所述功能:hw_smsd.py
(注意下读写串口可能需要 root 权限)

#!/usr/bin/env python
#encoding: utf-8

# Copyright (C) 2013 @XiErCh
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import time
import serial
import smtplib
from datetime import datetime


LOGFILE_PATH  = 'mail.log'
TTY_DEV_PATH  = '/dev/ttyUSB0'

SENDER_EMAIL  = 'hw-smsd@somehost'
NOTICE_EMAIL  = 'your@email'
CALL_SMSREPLY = u'抱歉,本号码暂时停用。请拨打 13800138000 联系我,谢谢。'

class ATSerial(serial.Serial):
    '''Send a AT command and return the response or raise a error.
    '''
    # Please see HUAWEI CDMA Datacard Modem AT Command Interface Specification
    # for detial.
    def at(self, cmd):
        self.write('AT%s\r\n' % cmd)
        self.flush()
        self.readline()
        rsp = ''
        while True:
            l = self.readline().strip()
            if not l:
                continue
            elif l == 'OK':
                return rsp
            elif l == 'ERROR':
                raise IOError('AT: ERROR')
            elif l == 'COMMAND NOT SUPPORT':
                raise IOError('AT: COMMAND NOT SUPPORT')
            elif l == 'TOO MANY PARAMETERS':
                raise IOError('AT: TOO MANY PARAMETERS')
            rsp += '%s\n' % l


def get_serial():
    return ATSerial(TTY_DEV_PATH)


def sendmail(msg, subject='',fromaddr=SENDER_EMAIL, toaddr=NOTICE_EMAIL):
    s = smtplib.SMTP('localhost')
    msg = u"From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s" \
            % (fromaddr, toaddr, subject, msg)
    s.sendmail(fromaddr, toaddr, msg.encode('utf-8'))
    logfile.write(msg.encode('utf-8') + '\n\n')
    logfile.flush()
    s.quit()


def sendsms(s, number, text, number_type=0):
    logfile.write('SMS to %s:\n%s\n\n' % (number, text))
    logfile.flush()
    s.write('AT^HCMGS="%s",%s\r' % (number, number_type))
    s.flush()
    time.sleep(0.1)
    s.write(text.encode('utf-16-be') + '\x00\x1a')
    while True:
        l = s.readline().strip()
        if l == 'OK':
            return
        elif l.startswith('+CMS ERROR:'):
            raise IOError(l)


def e_new_sms(s, opt):
    # opt[0]     callerID
    #    [1:7]   yyyy,mm,dd,hh,mm,ss
    #    [7]     lang
    #    [8]     format
    #    [9]     length
    #    [10-13] ...
    text = s.read(int(opt[9])).decode('utf-16-be')
    s.read(3) # Ignore ^Z\r\n
    send_time = "%s-%s-%s %s:%s:%s" % tuple(opt[1:7])
    recv_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    mailsubject = u'来自 %s 的短信' % opt[0]
    mailtext = u'%s\r\n\r\n----\r\n发送号码:%s\r\n发送日期:%s\r\n接收日期:%s' \
            % (text, opt[0], send_time, recv_time)
    sendmail(mailtext, mailsubject)
    print("SMS => E-mail")
    s.at('+CNMA') # ack


def e_income_call(s, opt):
    # opt[0] number
    #    [1] type
    #    [5] CLI validity
    if not opt[0]:
        if opt[5] == '1':
            opt[0] = u'隐藏号码'
        else:
            opt[0] = u'未知号码'
    mailsubject = u'来自 %s 的来电' % opt[0]
    mailtext = u'来电者:%s\r\n来电时间:%s' \
            % (opt[0], datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    sendmail(mailtext, mailsubject)
    print("Call => E-mail")
    s.at('+CHV') # reject
    if opt[0].startswith('1'):
        sendsms(s, opt[0], CALL_SMSREPLY, opt[1])
        print("Call <= SMS")


def loop(s):
    line = s.readline().strip()
    if not line:
        return
    elif line == 'RING':
        return
    try:
        cmd, rsp = line.split(':', 1)
        rsp = rsp.strip()
        opt = rsp.split(',')
    except ValueError:
        print('unknow [%s]' % line)
        return

    if cmd == '^HCMT':
        e_new_sms(s, opt)
    elif cmd == '+CLIP':
        e_income_call(s, opt)

    else:
        print('unknow - %s:' % cmd)
        print(opt)


def main():
    s = get_serial()

    # SMS Parameter Selection:
    # ^HSMSSS=<ack>,<prt>,<fmt>,<prv>
    #   <fm>  6: Unicode
    s.at("^HSMSSS=0,0,6,0")

    # New SMS Notification Setting:
    # +CNMI=[<mode>[,<mt>[,<bm>[,<ds>[,<bfr>]]]]]
    s.at("+CNMI=1,2")

    #sendmail('test', 'sendmail test')
    while True:
        loop(s)

if __name__ == '__main__':
    logfile = open(LOGFILE_PATH, 'a')
    main()

还比较简陋,但运行了几天没问题,就发上来~怎么说也算留个思路吧。

改进

记得刚才说的,这张上网卡有带一个 2.5mm 插口么,
和 Cubieboard 的 Line-In, 耳机口 相连,再装个 Asterisk 配置一下,一个自己的 SIP 网络电话就架成了~

不过目前来说,我对这功能需求并不迫切呢..

]]>
/p/sms2email/feed/ 14
Shadowsocks-java /p/ss-java/ /p/ss-java/#comments Fri, 29 Mar 2013 16:49:49 +0000 http://ouno.tk/?p=347600 Update 130905: 注意这只是一个练习,日常使用推荐 Pythonnode.js

Shadowsocks-java你懂的 软件的客户端的 java 版本。

Python, node.js, Go, C, C#, Ruby, Javascript 各种版本都有了,似乎没见到 Java 版..(Android 客户端用的是 C 版
抱着 改改然后出安卓收费版 积攒一下经验值的想法,试着用 Java 重写了一遍这玩意..

获得成就:

  • 习得 java Socket 编程基础
  • 明白 select 是何物
  • 习得 Socks5 协议基础
  • 了解归并排序
  • ……

只写了原始的 table 加密,归并排序那段是抄现成的。
后来才知道有 Arrays.sort(T[], Comparator) 无需自己写排序,但 byte[] 要转成 Byte[] (?) 我怕影响效率就没动了。

网络那段和 Python 版的一样,用了线程和 select。每个连接一个线程,转发数据用 Selector 。期间反复参考了这篇文章
本想全改 select 的但是当时还不太明白 Selector 怎么用,下次也许能写出来了。

具体用法参照 README。传送门在文章开头。

]]>
/p/ss-java/feed/ 7
[已失效] 找回cnBeta评论 /p/cbcom/ /p/cbcom/#comments Sat, 30 Jun 2012 06:44:55 +0000 http://xierch.tk/?p=347357 安装/使用方法:

  1. 下载 Greasemonkey,Firefox 用户请猛击这里安装扩展,Chrome 可直接安装(未测试);
  2.  请 猛击这里 (或这里) 安装“找回CB评论”脚本。(@mybeky 提供,感谢!说明

24小时内评论将直接显示。
超过24小时的,将调用第三方存档,目前仅支持找回热门评论。
存档包括 2011-12-02 之前、2012-11-18 之后大部分文章的热门评论。
每篇存档将在评论被隐藏前3分钟内完成。

UPDATE 2013-06-24: 重写了脚本,支持改版后的网站了。虽说原站风格太古董了也该改改,可是这改的确实不咋地,首先对浏览习惯的改变太大,其次配色总觉得有些不太对,比如热门评论这底色也太白了点吧.. = = .. 动态数据用 JSON 一次载入了,这倒是比之前载入两个 HTML 好多了。我抓评论也方便了不少。

右侧热门评论将从手机版中直接调取;
底部所有评论将优先检查服务器存档,若不存在则从CB手机版中调取。

服务器从6月28日(194427)开始,在被隐藏前10分钟内对每篇评论存档。
存档数据将保留全部数据,手机版的嵌套回复格式将丢失,支持反对举报回复失效。

附:服务器抓取评论的脚本(MIT 许可证)。

]]>
/p/cbcom/feed/ 1
[已失效] 找回cnBeta评论 – 油猴脚本 /p/cb-hotcom-script/ /p/cb-hotcom-script/#comments Sat, 24 Dec 2011 16:00:10 +0000 http://xierch.tk/?p=347314 UPDATE120630: 本文已过时,具体说明请移步这篇文章

这篇文章里讲过,cnBeta.COM 手机版未隐藏评论。写了个脚本抓评论。
今天把这个脚本般到GAE上去了。
兼容@mybeky的油猴脚本“The Lost Comments for cnbeta”,实现在浏览CB时直接还原热门评论~

安装/使用方法:

  1. 下载 Greasemonkey,Firefox 用户请猛击这里安装扩展,其他浏览器自行寻找;
  2. 猛击这里 安装修改过的“找回CB评论”脚本。

@mybeky 提供的服务比,优点:又可以用了,可以找回2011/01/28之前的评论,数据更新;
缺点:看CB心情随时可能悲剧,速度慢,不支持恢复底部所有评论,无法支持/反对/回复……

至于底下的所有评论…… – – 其实是我懒得搞了……
UPDATE120617: 支持找回底下所有评论了~ 虽然只有第一页.. 老用户请更新脚本
UPDATE120630: 对于6月28日(194427)之后的文章,将直接调用服务器存档,可保留嵌套回复格式、支持反对与回复。详见 这篇文章

不会JS,不会写浏览器扩展,不然可以在本地直接拉手机版CB的评论数据,方便快捷稳定…

]]>
/p/cb-hotcom-script/feed/ 1
ASS 字幕在线转换为 SRT /p/web-ass2srt/ /p/web-ass2srt/#respond Fri, 26 Aug 2011 08:34:11 +0000 http://xierch.tk/?p=347234 >> ass to srt 在线字幕转换:
http://lab.sorz.org/tools/asstosrt/

这就是之前写的那个asstosrt2.py脚本的GAE移植版
具体说明、源码请见:《[Python] ass字幕批量转srt – asstosrt2.py》

这个GAE移植版…可以说…相当简陋(丑陋)…

 暂不支持批量转换…所以只能供手头没工具时临时使用吧…
需要批量转换可以直接下载 asstosrt2.py 脚本…

#UPDATE111218:
支持上传ZIP压缩包批量转换了!如需离线使用仍可下载 asstosrt2.py 脚本。

#UPDATE120303:
已由GAE迁至VPS的Django上,更灵活些..

]]>
/p/web-ass2srt/feed/ 0
[Python] ASS 字幕批量转 SRT – asstosrt2.py /p/py-ass2srt/ /p/py-ass2srt/#comments Tue, 19 Jul 2011 17:01:33 +0000 http://xierch.tk/?p=347213 #UPDATE120423: 查看新版。本文所述版本已不再更新。
#UPDATA111218:
不想看以下大堆文字说明,请直接猛戳此处使用在线版本直接批量转换

电视、手机 都不支持 ASS 字幕 ,之前用 SrtEdit 转。
但后来遇到个字幕组,把 OP&ED 的字幕放在最前面,字幕顺序颠倒了,手机就不认了…
于是写了这个 Python 脚本

为了使用方便,只需要将ass文件全部选中,拖到 asstosrt2.py 上就好了
#UPDATE110903: 如果无法拖拽,可直接运行,将自动转换同目录下所有.ass文件。
再没有其他操作了…
如果没有错误,转换完窗口会直接关闭,在ass文件同目录下会生成srt文件

当然你需要先安装 Python 2.x 才行

下载 asstosrt2.py:
最新: GitHub | 历史:  SkyDrive | Google Docs

下载 Python 2.7:
Python.org


#UPDATA110903: 请确保 atslib.zip 与 asstosrt2.py 在同一目录下。

功能特点:

× 默认输出srt文件编码为 UTF-16 (Unicode / UCS-2 Little Endian)
    我电视手机刚好都支持这个编码
× 自动删除 {} 内的特效代码
    srt 不支持嘛
× 默认对字幕按时间进行重新排序
    我手机只要顺序一乱就罢工了,电视还没试过
× 默认删除带过渡特效的字幕
    例如顶部滚动显示“仅供研究,请在24小时内删除……”等,容易覆盖对白字幕
× 繁简体转换(默认禁用)
调用了部分维基百科的翻译规则,使用了部分 pyswim 项目代码
× 只显示第一行字幕(默认禁用)
    一些双语字幕将中文放置在第一行,启用后可简单删除 \N  后的内容

由于比较懒 🙂 ,如需修改默认设置,请直接编辑代码 48~52 行。

程序很简单,或者说很简陋,本来就是自己方便着用的东西嘛…200行..
Python 2.7, Windows 7 下调试无误,GPLv3
初学 Python 没几天,糟糕的代码,见笑了
P.s 不要吐槽排序部分代码  -_-||

#UPDATE 120306:
(Ver 0.4.6) 支持换行显示

#UPDATE 110923:
(Ver 0.4.5) 解决某些设备(如某些三星电视)完全无法识别字幕的问题。

#UPDATE 110903:
(Ver 0.4.4) 忽略文件编码错误,解决少量字幕转换失败的问题。
(Ver 0.4.3) 非拖拽模式增加转换.ssa文件。
(Ver 0.4.2) 增加繁简体转换功能;
直接运行将转换通目录下所有.ass文件。

#UPDATE 110723:
(Ver 0.3.2) 自动识别ASS文件编码,解决无法转换非 UTF-8 / ASCII 文件的问题;
增加了一点转换失败判断;加了个简短的说明文件并打包。

]]>
/p/py-ass2srt/feed/ 24
单词发音小工具 /p/engtool/ /p/engtool/#respond Tue, 19 Apr 2011 08:57:17 +0000 http://xierch.tk/?p=347186 这个小工具是我2008年11月写的…09年2月最后一次更新……
调用 Google 字典 的内容,没有任何技术含量,仅为方便使用..

这两天半期考翻出来用了下…
很蛋疼的只有发音这一个功能..所以只在某些少部分情况下有用……

下载地址: SkyDriveGoogle Docs

此单词发音软件的截图

附源码,易语言,GPL

#update 附带一说,这软件用的还是google.cn的数据..当年g.cn还在

]]>
/p/engtool/feed/ 0
小工具:快速恢复被隐藏的根目录文件夹 /p/foldersx/ /p/foldersx/#respond Sat, 01 May 2010 20:31:42 +0000 /foldersx.html 现在的U盘病毒都是一个思路,一个就是auturun.inf,另外就是隐藏原来的文件夹,用其他东西代替这些文件夹,欺骗运行。
解决也简单,删掉那些乱七八糟的东西就好了…
但为了更好地隐藏正常文件夹,那些病毒们都给文件夹打上了系统属性这属性无法直接在资源管理器里修改…

于是本工具就诞生了…

软件截图
如图所示,软件极其简陋,但是至少比那个整半天的批处理好些吧…
下面那个“设置属性并退出”按钮,也是为了更快更方便地使用~ ^_^

下载地址:
Google Docs | Google Docs SSL

建议使用方法:
下载后将“目录属性.exe”解压至U盘根目录下,文件夹被隐藏时,运行此文件即可。

(易语言,开源,GPL)

]]>
/p/foldersx/feed/ 0