diff --git a/.gitignore b/.gitignore index 32858aa..e5a4d02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ + +.idea/ *.class # Mobile Tools for Java (J2ME) @@ -9,4 +11,4 @@ *.ear # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +hs_err_pid* \ No newline at end of file diff --git a/NSS.iml b/NSS.iml new file mode 100644 index 0000000..01178b1 --- /dev/null +++ b/NSS.iml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client_config.json b/client_config.json new file mode 100755 index 0000000..9e26dfe --- /dev/null +++ b/client_config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/conf/client_config.json b/conf/client_config.json new file mode 100755 index 0000000..a370ca3 --- /dev/null +++ b/conf/client_config.json @@ -0,0 +1 @@ +{"recent_address_list":["139.162.22.111"],"upload_speed":2740596,"download_speed":2859752,"server_port":150,"server_address":"139.162.22.111","protocal":"udp","socks5_port":1085,"auto_start":true} \ No newline at end of file diff --git a/conf/config.xml b/conf/config.xml new file mode 100755 index 0000000..e3dc6b6 --- /dev/null +++ b/conf/config.xml @@ -0,0 +1,9 @@ + + + 127.0.0.1 + 1085 + 127.0.0.1 + 1081 + aes-256-cfb + sssssssss + diff --git a/conf/pac.xml b/conf/pac.xml new file mode 100755 index 0000000..6b0c7bf --- /dev/null +++ b/conf/pac.xml @@ -0,0 +1,2478 @@ + + + gimpshop.com + *.*.* + directcreative.com + speedpluss.org + mingpaovan.com + wikinews.org + joachims.org + maiio.net + idv.tw + mail-archive.com + surfeasy.com.au + hihistory.net + alexlur.org + finalion.jp + nrk.no + nyt.com + cmule.com + gappp.org + givemesomethingtoread.com + yahoo.com.tw + robtex.com + thelifeyoucansave.com + perfspot.com + ugo.com + army.mil + amoiist.com + uderzo.it + zillionk.com + placemix.com + twitstat.com + erabaru.net + zhongmeng.org + tinypaste.com + wo.tc + youtu.be + prozz.net + tiananmenuniv.com + freemorenews.com + penchinese.net + mesotw.com + favotter.net + privacybox.de + liaowangxizang.net + firstfivefollowers.com + rfamobile.org + xanga.com + godfootsteps.org + dalailama.com + bigsound.org + retweetist.com + fizzik.com + bbg.gov + imagezilla.net + myforum.com.hk + imlive.com + webshots.com + ptt.cc + lsforum.net + bigfools.com + ziplib.com + makemymood.com + foxdie.us + juliereyc.com + 5i01.com + beijingspring.com + drewolanoff.com + twiffo.com + blinkx.com + michaelmarketl.com + views.fm + kcome.org + acgkj.com + branch.com + soupofmedia.com + autoproxy-gfwlist.googlecode.com + po2b.com + slideshare.net + dyndns.org + wikileaks.lu + sohcradio.com + allgirlsallowed.org + pts.org.tw + twitonmsn.com + 5maodang.com + idouga.com + whyx.org + peacehall.com + instapaper.com + pure18.com + greatfirewallofchina.org + lagranepoca.com + sstatic.net + rfa.org + sokamonline.com + im.tv + hulu.com + twiyia.com + sethwklein.net + dupola.com + dupola.net + coolaler.com + ngensis.com + googlepages.com + mp + freeweibo.com + novelasia.com + v70.us + zfreet.com + fgmtv.org + rssmeme.com + futuremessage.org + wsj.com + ieasynews.net + openleaks.org + benjaminste.in + asahichinese.com + twicsy.com + sweux.com + chrispederick.com + amzs.me + lkcn.net + woxinghuiguo.com + wefong.com + savemedia.com + livingstream.com + shangfang.org + hkzone.org + samsoff.es + kcsoftwares.com + twip.me + zannel.com + gaopi.net + emacsblog.org + tokyocn.com + robustnessiskey.com + wangruowang.org + internetfreedom.org + linpie.com + fc2.com + ghostery.com + taolun.info + bestforchina.org + m-team.cc + e-hentai.org + cna.com.tw + setty.com.tw + wikipedia.org + sorting-algorithms.com + kusocity.com + twttr.com + post.ly + backchina.com + thespeeder.com + tuidang.net + sinopitt.info + mongodb.org + orzistic.org + golang.org + betfair.com + oursogo.com + art-or-porn.com + omy.sg + middle-way.net + ap.org + dajiyuan.com + laqingdan.net + youmaker.com + anonymizer.com + cnavista.com.tw + nuvid.com + syx86.com + engadget.com + typepad.com + matsushimakaede.com + kickstarter.com + plm.org.hk + falsefire.com + fuckgfw.com + topnews.in + ihakka.net + hkatvnews.com + dfas.mil + pullfolio.com + yousendit.com + lupm.org + tweetdeck.com + t35.com + plunder.com + pbworks.com + tpi.org.tw + freerk.com + networkedblogs.com + hahlo.com + theampfactory.com + gvm.com.tw + coolder.com + civilhrfront.org + rnw.nl + apiary.io + e-gold.com + jitouch.com + youtubecn.com + livingonline.us + your-freedom.net + pct.org.tw + fringenetwork.com + epochtimes.jp + deck.ly + spinejs.com + tvants.com + kagyuoffice.org.tw + ventureswell.com + womensrightsofchina.org + smhric.org + 6-4.net + mash.to + ifanqiang.com + quadedge.com + openid.net + rangzen.org + fbcdn.net + page2rss.com + morbell.com + boxcar.io + freedomhouse.org + footwiball.com + shixiao.org + ecstart.com + desc.se + sod.co.jp + usa.gov + twbbs.tw + chromeadblock.com + rocmp.org + gardennetworks.org + njuice.com + dailyme.com + oclp.hk + search.com + hkhkhk.com + puffstore.com + advanscene.com + onlylady.cn + miroguide.com + centurys.net + planetsuzy.org + cdpwu.org + myav.com.tw + dw-world.com + fangbinxing.com + xuchao.org + usfk.mil + brandonhutchinson.com + rapidsharedata.com + qmzdd.com + foxbusiness.com + diigo.com + xml-training-guide.com + freeoz.org + blogimg.jp + twitterkr.com + tanc.org + anontext.com + twurl.nl + pilotmoon.com + fulue.com + turningtorso.com + sytes.net + mk5000.com + americangreencard.com + zhenghui.org + cao.im + 50webs.com + vtunnel.com + nintendium.com + xiezhua.com + sex8.cc + thedw.us + markmail.org + radioaustralia.net.au + seevpn.com + rileyguide.com + 908taiwan.org + lerosua.org + twitgoo.com + livestream.com + facesofnyfw.com + mpettis.com + pdetails.com + natado.com + fourthinternational.org + globalrescue.net + slinkset.com + chinaxchina.com + chinasocialdemocraticparty.com + marines.mil + chinese-hermit.net + nextmedia.com + jiruan.net + calameo.com + tweetboner.biz + vimperator.org + furl.net + wordsandturds.com + cnn.com + dvorak.org + suoluo.org + fly4ever.me + ntdtv.org + lsm.org + nytimes.com + summify.com + geohot.com + heqinglian.net + xinmiao.com.hk + skype.com + gtricks.com + uniteddaily.com.my + westkit.net + bill2-software.com + gstatic.com + nydus.ca + brizzly.com + wallpapercasa.com + bonbonme.com + mypopescu.com + ezpc.tk + justfreevpn.com + taipei.gov.tw + fxnetworks.com + cl.ly + theguardian.co + csdparty.com + labiennale.org + cpj.org + fw.cm + sogclub.com + weeewooo.net + iset.com.tw + pornrapidshare.com + qtweeter.com + fuckcnnic.net + 92ccav.com + yimg.com + eriversoft.com + hrcir.com + emule-ed2k.com + ghost.org + twhirl.org + vevo.com + huaxia-news.com + giga-web.jp + broadbook.com + goldwave.com + dok-forum.net + ied2k.net + chinesen.de + myactimes.com + skykiwi.com + hugoroy.eu + conoyo.com + izaobao.us + alwaysdata.net + xvideos.com + iicns.com + foolsmountain.com + torrentcrazy.com + so-net.net.tw + xinsheng.net + scmp.com + zozotown.com + shopping.com + xjp.cc + matainja.com + supertweet.net + geometrictools.com + ibros.org + fangeming.com + shellmix.com + gov.tw + icl-fi.org + a-normal-day.com + a5.com.ru + apetube.com + biantailajiao.com + chosun.com + baidu.jp + philly.com + tweete.net + laogai.org + mingpaonews.com + gopetition.com + longtermly.net + realraptalk.com + gongwt.com + fooooo.com + gamebase.com.tw + in.com + vidoemo.com + xrea.com + morningsun.org + tibetalk.com + blogtd.org + helpzhuling.org + htmldog.com + mimivip.com + htl.li + tap11.com + yilubbs.com + zuola.com + pengyulong.com + provideocoalition.com + fan-qiang.com + twt.tl + ithome.com.tw + dy24k.info + chinainperspective.com + cms.gov + lookpic.com + ultravpn.fr + webs-tv.net + hakkatv.org.tw + wretch.cc + urbanoutfitters.com + mobileways.de + c-est-simple.com + myfreshnet.com + plays.com.tw + journalofdemocracy.org + cookingtothegoodlife.com + taiwandaily.net + bloomberg.de + catcatbox.com + thevivekspot.com + mingpaomonthly.com + plus28.com + tunnelbear.com + line.me + twt.fm + twipple.jp + premeforwindows7.com + ladbrokes.com + bookshelfporn.com + wikimapia.org + catfightpayperview.xxx + goagent.biz + bloodshed.net + catholic.org.hk + chuizi.net + uygur.org + googlesile.com + ka-wai.com + wujie.net + hkepc.com + bjzc.org + nexton-net.jp + entermap.com + brightkite.com + bwsj.hk + pdproxy.com + ustream.tv + lyricsquote.com + psblog.name + flightcaster.com + mad-ar.ch + gdzf.org + reuters.com + unblock.cn.com + whereiswerner.com + cdpweb.org + sugarsync.com + nuzcom.com + want-daily.com + helloqueer.com + cuiweiping.net + baby-kingdom.com + dotplane.com + ccdtr.org + wikileaks.pl + bot.nu + dalianmeng.org + vansky.com + latimes.com + google.co.jp + tvunetworks.com + futurechinaforum.org + hikinggfw.org + qoos.com + target.com + waqn.com + chinarightsia.org + guomin.us + cyberghostvpn.com + billywr.com + twittertim.es + felixcat.net + toodoc.com + yam.com + porn.com + stoptibetcrisis.net + xuchao.net + generesis.com + minimalmac.com + yidio.com + aolnews.com + newcenturymc.com + newcenturynews.com + shaunthesheep.com + newsminer.com + jwmusic.org + socialwhale.com + drtuber.com + devio.us + wikilivres.info + gmbd.cn + hkgreenradio.org + mtw.tl + ziddu.com + slavasoft.com + internationalrivers.org + ttv.com.tw + tv.com + securitykiss.com + akiba-online.com + wikimedia.org + aculo.us + bitly.com + breakingtweets.com + sinomontreal.ca + secretchina.com + gradconnection.com + scmpchinese.com + rfi.my + voagd.com + bebo.com + mobatek.net + atgfw.org + weiboleak.com + support + osfoora.com + hrichina.org + tibetwrites.org + mingpaony.com + chinatweeps.com + topify.com + transgressionism.org + slickvpn.com + stuffimreading.com + mizzmona.com + lester850.info + stackfile.com + uyghurcongress.org + bullog.org + 24smile.org + megurineluka.com + friendfeed.com + liudejun.com + fanswong.com + sexinsex.net + boxun.com + tiandixing.org + oizoblog.com + exploader.net + roodo.com + tbpic.info + putlocker.com + eevpn.com + dafagood.com + sinocast.com + opera.com + mpfinance.com + pornvisit.com + taiwannation.com.tw + ifjc.org + upload4u.info + prosiben.de + bayvoice.net + sina.com.tw + referer.us + trendsmap.com + fgmtv.net + readingtimes.com.tw + 1pondo.tv + xfm.pp.ru + xfiles.to + newtaiwan.com.tw + epochtimes-romania.com + 4chan.org + bbc.in + romanandreg.com + urlparser.com + peopo.org + ipicture.ru + dotsub.com + mathiew-badimon.com + rockmelt.com + twittbot.net + sockslist.net + keepandshare.com + avoision.com + coveringweb.com + unix100.com + sogoo.org + goldenmelody.com.tw + wanderinghorse.net + vot.org + chinacomments.org + wikileaks.ch + ronjoneswriter.com + bbsfeed.com + facebook.net + mymaji.com + iask.bz + tubecao.com + dontmovetochina.com + hidemyass.com + myparagliding.com + pandora.com + getcloudapp.com + klip.me + imagevenue.com + chinafreepress.org + streetvoice.com + zhe.la + hsjp.net + xh4n.cn + botanwang.com + dropbox.com + hellouk.org + animecrazy.net + navigeaters.com + s8forum.com + picturesocial.com + bullogger.com + 888.com + offbeatchina.com + seezone.net + frontlinedefenders.org + theblemish.com + internet.org + anthonycalzadilla.com + feelssh.com + rsf.org + lvhai.org + boardreader.com + owl.li + geocities.com + nobelprize.org + pornmm.net + wuerkaixi.com + sina.com.hk + heiyo.info + foxtang.com + tnaflix.com + tuidang.org + paperb.us + billypan.com + zvereff.com + openvpn.net + pastebin.com + kaiyuan.de + ameblo.jp + findbook.tw + ccthere.com + markmilian.com + goagentplus.com + cdpusa.org + newgrounds.com + xpdo.net + rapbull.net + innermongolia.org + feedbooks.mobi + tumblweed.org + feedzshare.com + blogcatalog.com + xcritic.com + lsmchinese.org + davidziegler.net + sneakme.net + hwinfo.com + vpnfire.com + law.com + tsemtulku.com + spb.com + i1.hk + parislemon.com + vimeo.com + grandtrial.org + holyspiritspeaks.org + 2008xianzhang.info + archive.is + zaobao.com + tmi.me + nobodycanstop.us + whylover.com + starp2p.com + dalailamaworld.com + lastfm.es + hkfront.org + pbxes.com + dnscrypt.org + getfreedur.com + bobulate.com + sevenload.com + lockdown.com + idsam.com + twitter4j.org + liansi.org + metacafe.com + twistory.net + zaozon.com + peeasian.com + mixero.com + thepiratebay.org + toutfr.com + tokyo-247.com + twreg.info + twitzap.com + bignews.org + tora.to + fileserve.com + muzu.tv + shitaotv.org + wengewang.org + geek-art.net + gongmeng.info + china21.com + wenhui.ch + uni.cc + feedburner.com + webfee.tk + sharecool.org + sex-11.com + vanemu.cn + marc.info + fapdu.com + coolloud.org.tw + verizon.net + sacom.hk + imdb.com + wikiwiki.jp + wufi.org.tw + bt95.com + hackthatphone.net + googledrive.com + neverforget8964.org + naver.jp + yong.hu + israbox.com + iask.ca + duckduckgo.com + riku.me + prestige-av.com + alwaysdata.com + ogaoga.org + org.uk + williamhill.com + expatshield.com + secureserver.net + gardennetworks.com + ntdtv.co + actimes.com.au + tjholowaychuk.com + huanghuagang.org + vanilla-jp.com + nsc.gov.tw + ntdtv.ca + wwitv.com + chinaaffairs.org + privatetunnel.com + kinghost.com + cdig.info + usgs.gov + hkreporter.com + newscn.org + simpleproductivityblog.com + box.net + freexinwen.com + scriptspot.com + chenguangcheng.com + karayou.com + saiq.me + heungkongdiscuss.com + ggssl.com + zhuichaguoji.org + china101.com + hideipvpn.com + sina.com + orn.jp + gartlive.com + clientsfromhell.net + allinfa.com + ccavtop10.com + twittergadget.com + cecc.gov + opendemocracy.net + clipfish.de + xskywalker.com + paint.net + vcfbuilder.org + procopytips.com + internetdefenseleague.org + pidown.com + openinkpot.org + mobypicture.com + cdnews.com.tw + lovequicksilver.com + singtao.ca + soc.mil + woeser.com + weijingsheng.org + doubleaf.com + hanunyi.com + tinychat.com + mp3ye.eu + 9bis.com + qkshare.com + time.com + newspeak.cc + tripod.com + chevronwp7.com + spencertipping.com + jackjia.com + c-spanvideo.org + zonaeuropa.com + minghui-school.org + stupidvideos.com + mingpaosf.com + tiscali.it + hongzhi.li + hihiforum.com + moztw.org + slheng.com + flnet.org + chinayouth.org.hk + twitiq.com + chinaaid.org + vaayoo.com + userdefined2.com + bloglines.com + whydidyoubuymethat.com + pixnet.net + photofocus.com + laomiu.com + songjianjun.com + genuitec.com + com.uk + monitorchina.org + t66y.com + files2me.com + wforum.com + gaeproxy.googlecode.com + bestvpnservice.com + killwall.com + tchrd.org + chinamz.org + feministteacher.com + shadowsocks.org + wattpad.com + wow-life.net + twitvid.com + twitter.jp + kzeng.info + thebodyshop-usa.com + youxu.info + lianyue.net + youtube.com + zhreader.com + tcno.net + ncn.org + 12bet.com + tweeplike.me + analyze-v.com + edubridge.com + cari.com.my + ezpeer.com + 2000fun.com + bnrmetal.com + nf.id.au + sowers.org.hk + yzzk.com + tampabay.com + danke4china.net + epochtimes.co.kr + nowtorrents.com + atlaspost.com + chinaway.org + stickam.com + dotheyfolloweachother.com + asianews.it + fmnnow.com + 9001700.com + showtime.jp + thetrotskymovie.com + vimgolf.com + kendincos.net + kurtmunger.com + igvita.com + maruta.be + xtube.com + qusi8.net + hk-pub.com + nurgo-software.com + byethost8.com + freebearblog.org + touch99.com + graphis.ne.jp + myeclipseide.com + linux-engineer.net + great-roc.org + rthk.hk + chinainperspective.net + ozchinese.com + twilio.com + istockphoto.com + sinoants.com + goodreaders.com + asiaharvest.org + lidecheng.com + t.co + twstar.net + epochtimes.com + ilove80.be + new-akiba.com + xmusic.fm + ntdtv.ru + tvboxnow.com + wisevid.com + hku.hk + zsrhao.com + bet365.com + power.com + ernestmandel.org + boxunblog.com + geocities.jp + tibetonline.tv + fanqianghou.com + modfetish.com + jobso.tv + ait.org.tw + ow.ly + ignitedetroit.net + topshare.us + unholyknight.com + cctongbao.com + neighborhoodr.com + sinocism.com + twitthat.com + ranyunfei.com + sharpdaily.com.hk + porn2.com + hyperrate.com + minzhuhua.net + ganges.com + tweepmag.com + ipvanish.com + idiomconnection.com + bitshare.com + iconpaper.org + mcfog.com + dajiyuan.eu + over-blog.com + tynsoe.org + homeservershow.com + khmusic.com.tw + dabr.me + hiitch.com + tmagazine.com + zuo.la + kissbbao.cn + tycool.com + skyhighpremium.com + kui.name + eyevio.jp + yyii.org + proxy.org + thomasbernhard.org + itweet.net + futureme.org + greatzhonghua.org + muzi.net + alvinalexander.com + fqrouter.com + hua-yue.net + skimtube.com + duckmylife.com + twitter.com + lenwhite.com + epochtimes.se + tokyo-hot.com + asdfg.jp + cnd.org + imageshack.us + getjetso.com + pubu.com.tw + yymaya.com + seesmic.com + videomo.com + hotpotato.com + retweeteffect.com + warehouse333.com + sproutcore.com + getsmartlinks.com + heix.pp.ru + sadpanda.us + aboluowang.com + jayparkinsonmd.com + fuckgfw.org + wangafu.net + bralio.com + sourceforge.net + pornstarclub.com + wordboner.com + jqueryui.com + mcadforums.com + freegao.com + twibs.com + ccue.com + wanglixiong.com + zhanbin.net + aol.com + kompozer.net + plusbb.com + tweetymail.com + simplecd.org + jbtalks.cc + privatepaste.com + lalulalu.com + fastly.net + freetibet.org + nuexpo.com + businessweek.com + ssh91.com + isgreat.org + 666kb.com + hrw.org + tidyread.com + ajaxplorer.info + userdefined.com + caobian.info + keso.cn + incredibox.fr + twibbon.com + isuntv.com + tvider.com + helpeachpeople.com + hutianyi.net + amnesty.org + xys.org + namsisi.com + redtube.com + teamseesmic.com + utom.us + tibet.org.tw + md-t.org + zhongguotese.net + msguancha.com + perlhowto.com + multiproxy.org + wengewang.com + sexhu.com + 0rz.tw + zonble.net + jkforum.net + sis001.us + whatblocked.com + cotweet.com + xuite.net + citizenlab.org + faststone.org + vapurl.com + value-domain.com + erights.net + anobii.com + pign.net + mog.com + fsurf.com + fredwilson.vc + zacebook.com + hechaji.com + x-berry.com + tkforum.tk + pagodabox.com + dl-laby.jp + thesartorialist.com + soup.io + youporn.com + dayabook.com + dailidaili.com + mx981.com + fangong.org + chinaaid.us + powercx.com + 9bis.net + duplicati.com + 141hongkong.com + bonjourlesgeeks.com + interestinglaugh.com + ippotv.com + peerpong.com + 7capture.com + uhrp.org + freewallpaper4.me + marco.org + trtc.com.tw + here4news.com + mixpod.com + fengzhenghu.com + taiwan-sex.com + xiaod.in + packetix.net + im88.tw + epochtimes.ru + chinatimes.com + j.mp + voachinese.com + laoyang.info + codeshare.io + dailymotion.com + new-3lunch.net + bcc.com.tw + news100.com.tw + voachineseblog.com + eamonnbrennan.com + topstyle4.com + wpoforum.com + freealim.com + vpngate.net + x1949x.com + twitterfeed.com + palacemoon.com + avdb.in + mhradio.org + webworkerdaily.com + fillthesquare.org + dadazim.com + thehousenews.com + yvesgeleyn.com + loved.hk + dontfilter.us + catholic.org.tw + civicparty.hk + on.cc + zarias.com + ccue.ca + pastie.org + web2project.net + aisex.com + curvefish.com + slime.com.tw + marxists.org + chubun.com + liuhanyu.com + boxun.tv + xuzhiyong.net + joeedelman.com + dynawebinc.com + jbtalks.com + iu45.com + w3.org + davidslog.com + tv-intros.com + dafahao.com + mingpaotor.com + nekoslovakia.net + epochtimes.de + zhong.pp.ru + chinalawtranslate.com + freessh.us + cuhkacs.org + fanglizhi.info + fdbox.com + ozyoyo.com + panluan.net + shenzhoufilm.com + cafepress.com + debian.org + fanyue.info + worldcat.org + dtiserv2.com + mgstage.com + xnxx.com + co.hk + twitpic.com + path.com + nicovideo.jp + zeutch.com + newchen.com + lrfz.com + freeopenvpn.com + pbs.org + myspace.com + idaiwan.com + foxsub.com + tiffanyarment.com + get-digital-help.com + secretgarden.no + mixx.com + twibase.com + uploaded.to + ialmostlaugh.com + tzangms.com + thechinabeat.org + co.tv + jingpin.org + facebook.com + space-scape.com + dadi360.com + tomsc.com + 4sq.com + myaudiocast.com + friendfeed-media.com + nodesnoop.com + newyorktimes.com + rxhj.net + qienkuen.org + uwants.net + culture.tw + identi.ca + list.ly + duckload.com + videobam.com + stoweboyd.com + zkaip.com + vpnpronet.com + nps.gov + wqyd.org + togetter.com + taipeisociety.org + torproject.org + tw + gclooney.com + googlesyndication.com + hkej.com + blog.de + koolsolutions.com + mmmca.com + great-firewall.com + chrlcg-hk.org + movabletype.com + immigration.gov.tw + dw-world.de + anchorfree.com + gospelherald.com + purevpn.com + voacantonese.com + djangosnippets.org + hasaowall.com + tweetwally.com + pokerstrategy.com + xing.com + podictionary.com + stickeraction.com + derekhsu.homeip.net + sis.xxx + wzyboy.im + buzzurl.jp + twistar.cc + taa-usa.org + appledaily.com + nysingtao.com + tuxtraining.com + cz.cc + xbookcn.com + witopia.net + wenyunchao.com + travelinlocal.com + thetibetpost.com + xyy69.com + szbbs.net + canadameet.com + backpackers.com.tw + uncyclopedia.info + helloandroid.com + greatfirewallofchina.net + tibetanyouthcongress.org + alexdong.com + alabout.com + sexandsubmission.com + pbxes.org + hutong9.net + verybs.com + blogspot.jp + avidemux.org + alkasir.com + shinychan.com + yasukuni.or.jp + shenshou.org + tube.com + xizang-zhiye.org + galenwu.com + areca-backup.org + bao.li + multiupload.com + greenvpn.net + thedieline.com + berlintwitterwall.com + dfanning.com + molihua.org + hungerstrikeforaids.org + npa.go.jp + 10musume.com + wet123.com + newlandmagazine.com.au + gather.com + bcchinese.net + sesawe.net + usejump.com + funp.com + mh4u.org + wukangrui.net + jeanyim.com + chinaworker.info + maxgif.com + pixelqi.com + sjum.cn + mgoon.com + cbsnews.com + chengmingmag.com + all-that-is-interesting.com + soumo.info + xpud.org + naacoalition.org + anyu.org + latelinenews.com + s1heng.com + e-info.org.tw + globaljihad.net + wenku.com + mitbbs.com + kakao.com + wiredbytes.com + qxbbs.org + yx51.net + popyard.org + state.gov + yunchao.net + dolc.de + ironpython.net + alasbarricadas.org + oxid.it + tweetmeme.com + rerouted.org + disp.cc + aiweiweiblog.com + 123rf.com + macrovpn.com + badoo.com + ukchinese.com + memrijttm.org + mycould.com + mixedmedialabs.com + frommel.net + mininova.org + shahamat-english.com + yegle.net + teck.in + bbsland.com + blogtd.net + sshtunnel.googlecode.com + popularpages.net + savevid.com + pornoxo.com + lsmkorean.org + tiney.com + netme.cc + squarespace.com + hkgolden.com + voatibetan.com + speckleapp.com + newtalk.tw + shkspr.mobi + politicalchina.org + ddc.com.tw + thepiratebay.se + linuxreviews.org + cdp1998.org + twisternow.com + 881903.com + moby.to + woopie.tv + zdnet.com.tw + nch.com.tw + dojin.com + ned.org + ibiblio.org + fakku.net + wuala.com + daxa.cn + lightbox.com + yhcw.net + iphonix.fr + twit2d.com + netflix.com + gutteruncensored.com + hdtvb.net + shapeservices.com + westernwolves.com + psiphon.ca + rthk.org.hk + washeng.net + purepdf.com + larsgeorge.com + hloli.net + co.uk + twbbs.net.tw + zgzcjj.net + linkideo.com + softether.co.jp + phuquocservices.com + drgan.net + pcdiscuss.com + sitemaps.org + abc.pp.ru + linuxtoy.org + thedailywh.at + addictedtocoffee.de + getchu.com + geekerhome.com + greatroc.org + alternate-tools.com + marxist.com + kanzhongguo.com + greatroc.tw + pk.com + palmislife.com + dlsite.com + qooza.hk + crossthewall.net + twbbs.org + xinshijue.com + shvoong.com + woopie.jp + hqcdp.org + freenewscn.com + hkjp.org + stoneip.info + googleusercontent.com + amazon.com + old-cat.net + shadow.ma + instagram.com + ht.ly + sydneytoday.com + olympicwatch.org + whippedass.com + tafaward.com + falunart.org + unknownspace.org + tweetrans.com + jyxf.net + vmixcore.com + uushare.com + wikileaks.de + flickrhivemind.net + sis001.com + workatruna.com + memedia.cn + gpass1.com + megarotic.com + pikchur.com + dev102.com + zengjinyan.org + centralnation.com + puffinbrowser.com + pandora.tv + amiblockedornot.com + zhinengluyou.com + bannedbook.org + chinesenewsnet.com + nokogiri.org + wolfax.com + ifcss.org + pwned.com + thumbzilla.com + icerocket.com + koornk.com + leecheukyan.org + theqii.info + blip.tv + tweetbackup.com + updatestar.com + gzone-anime.info + 1984bbs.org + penthouse.com + ff.im + uploadstation.com + expofutures.com + alliance.org.hk + wearn.com + efcc.org.hk + zattoo.com + askynz.net + zaobao.com.sg + heartyit.com + qixianglu.cn + bettween.com + gun-world.net + kenengba.com + iphone-dev.org + crackle.com + twftp.org + zlib.net + multiply.com + lipuman.com + monlamit.org + porntube.com + tunein.com + uwants.com + gotw.ca + tumutanzi.com + opera-mini.net + dizhidizhi.com + pbwiki.com + ruyiseek.com + 12vpn.com + eltondisney.com + free.fr + 1bao.org + extremetube.com + yeelou.com + corumcollege.com + merit-times.com.tw + exblog.co.jp + hkheadline.com + uocn.org + wikileaks.org + taiwanyes.com + chinesepen.org + itaboo.info + thisiswhyyouarefat.com + martincartoons.com + theinternetwishlist.com + twitgether.com + hecaitou.net + collateralmurder.com + baixing.me + lesscss.org + uk.to + wikisource.org + nanyang.com + wikia.com + michaelanti.com + 2shared.com + chinagreenparty.org + fireofliberty.org + isohunt.com + ibtimes.com + meirixiaochao.com + rutube.ru + erepublik.com + briefdream.com + vocn.tv + ironicsoftware.com + htxt.it + mayimayi.com + businesstimes.com.cn + dayoneapp.com + beijing1989.com + kingdomsalvation.org + vpnbook.com + ping.fm + pentalogic.net + wan-press.org + hudatoriq.web.id + url.com.tw + duihua.org + bowenpress.com + fotop.net + liveleak.com + tvb.com + ulike.net + 365singles.com.ar + calebelston.com + turbobit.net + liujianshu.com + daylife.com + tuitui.info + allinfo.com + lsd.org.hk + mingjinglishi.com + qx.net + wepn.info + tenacy.com + parade.com + mobile01.com + cynscribe.com + lockestek.com + dtic.mil + jinhai.de + x-art.com + atchinese.com + gazotube.com + nownews.com + 64wiki.com + bloglovin.com + v-state.org + popyard.com + easyweb.hk + oiktv.com + ytht.net + willw.net + voy.com + chinahush.com + eyespirit.info + wangjinbo.org + dowei.org + tianhuayuan.com + ncol.com + goagent.googlecode.com + orzdream.com + noobbox.com + gongminliliang.com + heywire.com + cdjp.org + code1984.com + gzm.tv + sharebee.com + youthbao.com + chinadigitaltimes.net + tagwalk.com + chinagfw.org + wenxuecity.com + veoh.com + dongyangjing.com + lizhizhuangbi.com + tangben.com + logbot.net + fc2blog.net + techlifeweb.com + junefourth-20.net + seapuff.com + blogspot.hk + waikeung.org + jinbushe.org + my-proxy.com + kun.im + shodanhq.com + dw.de + kimy.com.tw + fflick.com + sino-monthly.com + slutload.com + postadult.com + falundafa.org + ifttt.com + yi.org + tube8.com + epochtimes.ie + opnir.com + marguerite.su + chenpokong.com + 2-hand.info + dit-inc.us + wikibooks.org + longhair.hk + dxiong.com + plixi.com + ntu.edu.tw + weekmag.info + img.ly + tuanzt.com + bit.ly + pornhub.com + mihua.org + ck101.com + wikileaks.eu + wallornot.org + softether.org + joeyrobert.org + twapperkeeper.com + rushbee.com + zoho.com + sendspace.com + proxomitron.info + allmovie.com + google.com + badassjs.com + howtoforge.com + fanqiangyakexi.net + googlevideo.com + torvpn.com + qvodzy.org + hacken.cc + ismprofessional.net + presentationzen.com + huping.net + velkaepocha.sk + chinamule.com + trulyergonomic.com + atnext.com + nccwatch.org.tw + globalmuseumoncommunism.org + streamingthe.net + qanote.com + falunhr.org + thehungrydudes.com + wordpress.com + nexttv.com.tw + discuss.com.hk + usmc.mil + basetimesheightdividedby2.com + oauth.net + wetpussygames.com + zshare.net + 89-64.org + linglingfa.com + juziyue.com + ruanyifeng.com + cnyes.com + aiph.net + skybet.com + vatn.org + hypeshell.com + megavideo.com + rojo.com + tibetfund.org + awardwinningfjords.com + falundafamuseum.org + jiepang.com + eulam.com + pchome.com.tw + thehun.net + tistory.com + blingblingsquad.net + nakido.com + fzh999.net + creaders.net + hkbf.org + wqlhw.com + overlapr.com + us.to + tl.gd + ourdearamy.com + epochtimes.fr + google.com.hk + wapedia.mobi + allaboutalpha.com + graylog2.org + metrolife.ca + gigporno.ru + moviefap.com + twtkr.com + rferl.org + shwchurch3.com + sysadmin1138.net + electionsmeter.com + cyberctm.com + rsf-chinese.org + sparrowmailapp.com + sex.com + xuzhuoer.com + xmovies.com + duoweitimes.com + rapidshare8.com + chingcheong.com + xhamster.com + moegirl.org + freemoren.com + pornbase.org + danwei.org + greenparty.org.tw + van698.com + mlcool.com + uighurbiz.net + omgili.com + blogspot.in + sharpdaily.hk + jiehua.cz + livevideo.com + weblagu.com + nlfreevpn.com + zyzc9.com + wiredpen.com + panoramio.com + sopcast.org + mysinablog.com + sogrady.me + teashark.com + etizer.org + westca.com + forums-free.com + oikos.com.tw + 315lz.com + letscorp.net + powerapple.com + hk32168.com + 51.ca + salvation.org.hk + rfi.fr + getiton.com + awflasher.com + getlantern.org + i2runner.com + hidecloud.com + gcpnews.com + marxist.net + vegorpedersen.com + twifan.com + tweetphoto.com + ovi.com + cubicle17.com + greatfire.org + gabocorp.com + tibetonline.com + change.org + turbotwitter.com + chinaaid.me + thisav.com + free-ssh.com + tubewolf.com + xgmyd.com + gfw.org.ua + chinesedailynews.com + viki.com + ecministry.net + mooo.com + sinoquebec.com + yahoo.co.jp + slandr.net + favorious.com + rhcloud.com + sthoo.com + softwarebychuck.com + illusionfactory.com + efksoft.com + staticflickr.com + freenet-china.org + cams.com + 21andy.com + megabyet.net + greatfirewall.biz + islam.org.hk + tiananmenmother.org + mirrorbooks.com + chinageeks.org + dongtaiwang.com + twimg.com + hardsextube.com + soundcloud.com + 4bluestones.biz + tweepguide.com + twitlonger.com + revleft.com + october-review.org + isunaffairs.com + codeboxapp.com + zinio.com + snaptu.com + fc2china.com + sendoid.com + giganews.com + huaglad.com + youthwant.com.tw + eventful.com + yeeyi.com + istef.info + playboy.com + youjizz.com + thelius.org + imkev.com + websitepulse.com + listorious.com + open.com.hk + youversion.com + rlwlw.com + twitcause.com + flickr.com + ajsands.com + softether-download.com + waiwaier.com + site90.net + hootsuite.com + dongtaiwang.net + telecomspace.com + delcamp.net + dalailama.ru + vpnpop.com + 301works.org + chinaeweekly.com + youpai.org + echofon.com + nokola.com + tsctv.net + aol.ca + tsunagarumon.com + hinet.net + dropboxusercontent.com + cherrysave.com + mondex.org + dwnews.com + hjclub.info + h1n1china.org + raidcall.com.tw + goofind.com + weiming.info + hotspotshield.com + sopcast.com + aobo.com.au + fangongheike.com + i2p2.de + kingstone.com.tw + proxifier.com + twilog.org + oursteps.com.au + twittermail.com + reflectivecode.com + freechal.com + fail.hk + tt1069.com + 6park.com + piring.com + internetpopculture.com + tuite.googlecode.com + vpngate.jp + ub0.cc + zootool.com + huaxin.ph + melon-peach.com + d0z.net + cenci.tk + tianzhu.org + hkptu.org + gamer.com.tw + wellplacedpixels.com + recordhistory.org + exblog.jp + tsquare.tv + renminbao.com + brucewang.net + sesawe.org + vincnd.com + edoors.com + southnews.com.tw + etaiwannews.com + malaysiakini.com + udn.com + am730.com.hk + wexiaobo.org + unicode.org + soifind.com + favstar.fm + zomobo.net + braumeister.org + sammyjs.org + wujieliulan.com + revver.com + twitturly.com + getsocialscope.com + compython.net + webbang.net + citizensradio.org + gowalla.com + paper.li + dtiblog.com + sejie.com + meteorshowersonline.com + faydao.com + trialofccp.org + fb.com + comedycentral.com + linksalpha.com + zmw.cn + tweetmylast.fm + blogspot.fr + 6v6dota.com + omnitalk.com + idlcoyote.com + ning.com + libertytimes.com.tw + democrats.org + orchidbbs.com + china21.org + bbcchinese.com + af.mil + pin6.com + sankaizok.com + feer.com + avaaz.org + bloomfortune.com + sfileydy.com + nanyangpost.com + python.com + sandnoble.com + read100.com + classicalguitarblog.net + buugaa.com + amnestyusa.org + thereallove.kr + antiwave.net + fawanghuihui.org + x-wall.org + daolan.net + gfwinterceptor.googlecode.com + taiwanus.net + seraph.me + szetowah.org.hk + yuanming.net + geekmanuals.com + guancha.org + chinayuanmin.org + nga.mil + my903.com + archive.org + tamiaode.tk + netlog.com + onmoon.com + jiaoyou8.com + twibble.de + gaymap.cc + xinhuanet.org + yorkbbs.ca + scribd.com + blogspot.com + taragana.com + kl.am + rti.org.tw + relaxbbs.com + cellulo.info + owind.com + ucam.org + phonegap.com + navy.mil + tibet.net + uncyclomedia.org + vpncup.com + oopsforum.com + orientaldaily.com.my + hkbc.net + youtube-nocookie.com + winwhispers.info + savetibet.org + sohfrance.org + thegatesnotes.com + netcolony.com + kechara.com + break.com + cenews.eu + xxxx.com.au + muouju.com + h-china.org + voanews.com + proxyroad.com + tttan.com + dpp.org.tw + gdbt.net + hnjhj.com + thkphoto.com + la-forum.org + weiquanwang.org + nabble.com + tweetedtimes.com + okayfreedom.com + twimbow.com + cclife.org + zhenlibu.info + hkday.net + 1984bbs.com + iphonehacks.com + atebits.com + solozorro.tk + justtristan.com + pmates.com + waigaobu.com + naol.ca + adultfriendfinder.com + collateralmurder.org + al-qimmah.net + twitbrowser.net + jbtalks.my + mediafire.com + theatrum-belli.com + geocities.co.jp + listentoyoutube.com + somee.com + yahoo.com.hk + sexhuang.com + stonegames.net + dzze.com + python.com.tw + throughnightsfire.com + liuxiaotong.com + blogs.com + artsy.net + mashable.com + axureformac.com + 64tianwang.com + domain.club.tw + imageflea.com + wangruoshui.net + dougscripts.com + yogichen.org + bewww.net + gongm.in + shenyunperformingarts.org + sheikyermami.com + pekingduck.org + radiotime.com + chinasoul.org + kwongwah.com.my + blinw.com + atj.org.tw + aenhancers.com + ytimg.com + freevpn.nl + netfirms.com + windowsphoneme.com + xiaochuncnjp.com + chinainterimgov.org + xysblogs.org + epochtimes-bg.com + samair.ru + taiwankiss.com + hotpot.hk + books.com.tw + proxlet.com + gyalwarinpoche.com + focusvpn.com + dphk.org + oulove.org + filefactory.com + ifanr.com + urlborg.com + minzhuzhongguo.org + fb.me + icij.org + twindexx.com + twitreferral.com + linuxconfig.org + cts.com.tw + sanmin.com.tw + logmike.com + ultraxs.com + highrockmedia.com + theappleblog.com + taiwannews.com.tw + twa.sh + tacem.org + percy.in + apigee.com + itshidden.com + birdhouseapp.com + dongde.com + mefeedia.com + embr.in + clb.org.hk + chaturbate.com + strongvpn.com + asianwomensfilm.de + bugclub.org + xvedios.com + mpinews.com + x365x.com + arctosia.com + tiantibooks.org + worstthingieverate.com + kodingen.com + twyac.org + shizhao.org + budaedu.org + rcinet.ca + soh.tw + date.fm + izihost.org + threatchaos.com + paper-replika.com + mychat.to + farwestchina.com + inxian.com + xxbbx.com + taiwantt.org.tw + voa.mobi + huaren.us + twblogger.com + penchinese.com + everyday-carry.com + hotfile.com + sitetag.us + twaud.io + singtao.com + idemocracy.asia + chinainperspective.org + soundofhope.org + toonel.net + city9x.com + ufreevpn.com + sufeng.org + veempiire.com + delicious.com + thebcomplex.com + noypf.com + radiovaticana.org + igfw.net + chandoo.org + tomayko.com + tonyyan.net + ucdc1998.org + hkjc.com + xiaoma.org + so-ga.net + sapikachu.net + pacificpoker.com + unpo.org + sitebro.tw + blockcn.com + prayforchina.net + gmhz.org + spotify.com + gunsamerica.com + openwebster.com + liu.lu + muselinks.co.jp + 36rain.com + peacefire.org + cytode.us + yahoo.com + hongmeimei.com + waffle1999.com + globalvoicesonline.org + vft.com.tw + huluim.com + livestation.com + onmoon.net + pixnet.in + nanzao.com + tiananmenuniv.net + sinica.edu.tw + wezone.net + cochina.org + astonmartinnews.com + baywords.com + twitoaster.com + s135.com + iredmail.org + fring.com + spankwire.com + nytco.com + fofg.org + qtrac.eu + proxypy.net + tweepml.org + izles.net + cactusvpn.com + blogger.com + have8.com + retweetrank.com + mychinamyhome.com + hellotxt.com + chrispederick.net + goodreads.com + cjb.net + andfaraway.net + cdp2006.org + xyy69.info + youthnetradio.org + forum4hk.com + chinalawandpolicy.com + civisec.org + junauza.com + mihk.hk + palm.com + student.tw + svwind.com + chrlawyers.hk + pinoy-n.com + girlbanker.com + usacn.com + privateinternetaccess.com + hgseav.com + advertfan.com + xiaohexie.com + lazarsearlymusic.com + chinesetalks.net + bloomberg.com + fleshbot.com + higfw.com + vinniev.com + justin.tv + adultkeep.net + jieshibaobao.com + bfsh.hk + loiclemeur.com + bfnn.org + faiththedog.info + gtap.googlecode.com + picidae.net + epochweekly.com + free-gate.org + freelotto.com + himemix.com + tweetree.com + rfachina.com + truthcn.com + xcity.jp + newsancai.com + game735.com + caochangqing.com + liberal.org.hk + mrtweet.com + gamez.com.tw + qi-gong.me + steel-storm.com + turntable.fm + couchdbwiki.com + flecheinthepeche.fr + swift-tools.net + mmaaxx.com + fdc89.jp + emory.edu + eic-av.com + topsy.com + kyohk.net + pose.com + neolee.cn + edicypages.com + designerol.com + knowledgerush.com + ebookee.com + so-news.com + mthruf.com + getfoxyproxy.org + pathtosharepoint.com + logiqx.com + doxygen.org + say2.info + deutsche-welle.de + dabr.mobi + catch22.net + digitalnomadsproject.org + github.com + blogspot.de + pcdvd.com.tw + getyouram.com + compileheart.com + hidden-advent.org + megaporn.com + hougaige.com + aboutgfw.com + comefromchina.com + e-spacy.com + funf.tw + worldjournal.com + olumpo.com + finler.net + zoozle.net + vcf-online.org + wikimedia.org.mo + de-sci.org + stuffimreading.net + state168.com + cantonese.asia + fzh999.com + ipobar.com + topshareware.com + pokerstars.com + bloomberg.cn + qstatus.com + muzi.com + syx86.cn + changp.com + techparaiso.com + posterous.com + interfaceaddiction.com + cnitter.com + chinaaid.net + fscked.org + storagenewsletter.com + guishan.org + christusrex.org + syncback.com + tweetboard.com + powerpointninja.com + orient-doll.com + navicat.com + twittercounter.com + git-scm.com + martau.com + inmediahk.net + aliengu.com + taweet.com + 0to255.com + duping.net + tkcs-collins.com + trustedbi.com + nighost.org + babynet.com.hk + mmdays.com + appspot.com + dollf.com + epochtimestr.com + hellonewyork.us + 1eew.com + taiwannation.com + wezhiyong.org + csuchen.de + wahas.com + lookingglasstheatre.org + furinkan.com + observechina.net + chinachannel.hk + sysresccd.org + meetup.com + renyurenquan.org + chinese-memorial.org + canyu.org + jgoodies.com + china-week.com + pureconcepts.net + sowiki.net + kangye.org + br.st + yfrog.com + msn.com.tw + mingpao.com + crd-net.org + hk + googleapis.com + ydy.com + bipic.net + tibet.com + naitik.net + cuihua.org + gs-discuss.com + diaoyuislands.org + wozy.in + xthost.info + myopenid.com + hkdailynews.com.hk + glennhilton.com + christianstudy.com + freenetproject.org + ebookbrowse.com + gaoming.net + madmenunbuttoned.com + laptoplockdown.com + freakshare.com + e-traderland.net + twtrland.com + huhaitai.com + askstudent.com + yipub.com + truveo.com + tabtter.jp + franklc.com + weigegebyc.dreamhosters.com + iblogserv-f.net + kanzhongguo.eu + freewebs.com + ig.com.br + dwheeler.com + famunion.com + 173ng.com + minghui.org + isaacmao.com + perfectvpn.net + freeman2.com + sinonet.ca + jpopforum.net + sobees.com + free4u.com.ar + oyax.com + littlebigdetails.com + mingjingnews.com + sharkdolphin.com + limiao.net + jimoparty.com + assembla.com + dribbble.com + njactb.org + twiggit.org + lookatgame.com + darpa.mil + wtfpeople.com + tumblr.com + 1-apple.com.tw + diff --git a/conf/port_map.json b/conf/port_map.json new file mode 100755 index 0000000..15520e5 --- /dev/null +++ b/conf/port_map.json @@ -0,0 +1 @@ +{"map_list":[{"dst_port":8338,"listen_port":1085,"name":"fuckGFW"}]} \ No newline at end of file diff --git a/conf/update.properties b/conf/update.properties new file mode 100755 index 0000000..e62a421 --- /dev/null +++ b/conf/update.properties @@ -0,0 +1,2 @@ +version=-2 +url=http://baidu.com \ No newline at end of file diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml new file mode 100755 index 0000000..69d7d31 --- /dev/null +++ b/dependency-reduced-pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + NSS + NSS + 1.0-SNAPSHOT + + + + maven-compiler-plugin + + 1.8 + 1.8 + + + + maven-shade-plugin + 2.3 + + + package + + shade + + + + + net.fs.client.FSClient + + + + + + + + + + UTF-8 + + + diff --git a/finalspeed-debian b/finalspeed-debian new file mode 100755 index 0000000..980d212 --- /dev/null +++ b/finalspeed-debian @@ -0,0 +1,91 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: finalspeed +# Required-Start: $network $syslog $local_fs $remote_fs +# Required-Stop: $network $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start or stop the finalspeed server +# Description: Start or stop the finalspeed server +### END INIT INFO + +# Author: 91yun + +name=finalspeed +BIN=/fs/fs.sh +conf=/fs/fs.conf +logname=/fs/server.log + +start(){ + ulimit -s 65535 + ulimit -n 65535 + tram=$( free -m | awk '/Mem/ {print $2}' ) + if [ "$tram" -le 128 ]; then + nohup java -Xmx64M -XX:MaxGCPauseMillis=30 -jar /fs/fs.jar > $logname 2>&1 & + elif [ "$tram" -le 256 ]; then + nohup java -Xmx128M -XX:MaxGCPauseMillis=30 -jar /fs/fs.jar > $logname 2>&1 & + elif [ "$tram" -le 512 ]; then + nohup java -Xmx256M -XX:MaxGCPauseMillis=30 -jar /fs/fs.jar > $logname 2>&1 & + elif [ "$tram" -gt 512 ]; then + nohup java -Xmx512M -XX:MaxGCPauseMillis=30 -jar /fs/fs.jar > $logname 2>&1 & + fi + RETVAL=$? + if [ "$RETVAL" = "0" ]; then + tail $logname + echo "$name start success" + else + tail $logname + echo "$name start failed" + fi +} + +stop(){ + pid=`ps -ef | grep fs.jar | grep -v grep | awk '{print $2}'` + if [[ ! -z $pid ]]; then + ps -ef | grep fs.jar | grep -v grep | awk '{print $2}' | xargs kill -s 9 + RETVAL=$? + if [ "$RETVAL" = "0" ]; then + echo "$name stop success" + else + echo "$name stop failed" + fi + else + echo "$name is not running" + RETVAL=1 + fi +} + +status(){ + pid=`ps -ef | grep fs.jar | grep -v grep | awk '{print $2}'` + if [[ -z $pid ]]; then + echo "$name is not running" + RETVAL=1 + else + echo "$name is running with PID $pid" + tail $logname + RETVAL=0 + fi +} + +case "$1" in +'start') + stop + start + ;; +'stop') + stop + ;; +'status') + status + ;; +'restart') + stop + start + RETVAL=$? + ;; +*) + echo "Usage: $0 { start | stop | restart | status }" + RETVAL=1 + ;; +esac +exit $RETVAL \ No newline at end of file diff --git a/img/offline.png b/img/offline.png new file mode 100755 index 0000000..faa2049 Binary files /dev/null and b/img/offline.png differ diff --git a/pf.conf b/pf.conf new file mode 100644 index 0000000..2ead535 --- /dev/null +++ b/pf.conf @@ -0,0 +1 @@ +block drop quick proto tcp from any to 139.162.101.111 port = 150 diff --git a/pom.xml b/pom.xml new file mode 100755 index 0000000..3525ce0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,244 @@ + + + 4.0.0 + + NSS + NSS + 1.0-SNAPSHOT + + UTF-8 + + + + + src/main/java + target/classes + + + + maven-assembly-plugin + 2.6 + + + jar-with-dependencies + + + + net.fs.netty.Start + + + + + + make-assembly + package + + assembly + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-source + + + + src/main/java + + + + + + + + maven-resources-plugin + + + copy-resources + compile + + copy-resources + + + ${basedir}/apprun/conf + + + + ${basedir}/src/main/resources/ + true + + + + + + + + maven-compiler-plugin + 3.1 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + 1.8 + 1.8 + UTF-8 + + ${project.basedir}/libs + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy + package + + copy-dependencies + + + ${basedir}/apprun/${project.artifactId}/libs + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + + run + + package + + + + + + + + + + + + + + + + + io.netty + netty-all + 4.0.41.Final + + + org.bouncycastle + bcprov-jdk15on + 1.52 + + + com.mashape.unirest + unirest-java + 1.4.9 + + + log4j + log4j + 1.2.12 + + + commons-logging + commons-logging + 1.1.3 + + + + commons-cli + commons-cli + 1.3.1 + + + + com.alibaba + fastjson + 1.2.7 + + + + com.sun.jna + jna + 4.1.1 + system + ${project.basedir}/libs/jna.jar + + + + com.miglayout + miglayout-swing + 4.2 + + + + + org.pcap4j + pcap4j-core + 1.5.0 + + + + + + + org.pcap4j + pcap4j-packetfactory-static + 1.5.0 + + + + + + org.slf4j + slf4j-api + 1.7.21 + + + + org.slf4j + slf4j-nop + 1.7.21 + + + + \ No newline at end of file diff --git a/src/main/java/net/fs/cap/CapEnv.java b/src/main/java/net/fs/cap/CapEnv.java new file mode 100755 index 0000000..18fe7a5 --- /dev/null +++ b/src/main/java/net/fs/cap/CapEnv.java @@ -0,0 +1,530 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +import net.fs.netty.SocksServer; +import net.fs.rudp.Route; +import net.fs.utils.ByteShortConvert; +import net.fs.utils.MLog; +import org.pcap4j.core.*; +import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode; +import org.pcap4j.packet.*; +import org.pcap4j.packet.EthernetPacket.EthernetHeader; +import org.pcap4j.packet.IpV4Packet.IpV4Header; +import org.pcap4j.packet.TcpPacket.TcpHeader; +import org.pcap4j.util.MacAddress; + +import java.io.IOException; +import java.net.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.concurrent.LinkedBlockingQueue; + + +public class CapEnv { + + public MacAddress gateway_mac; + + public MacAddress local_mac; + + Inet4Address local_ipv4; + + public PcapHandle sendHandle; + + VDatagramSocket vDatagramSocket; + + String testIp_tcp=""; + + String testIp_udp="5.5.5.5"; + + String selectedInterfaceName=null; + + String selectedInterfaceDes=""; + + PcapNetworkInterface nif; + + private final int COUNT=-1; + + private final int READ_TIMEOUT=1; + + private final int SNAPLEN= 10*1024; + + HashMap tunTable=new HashMap(); + + LinkedBlockingQueue packetList=new LinkedBlockingQueue(); + + Random random=new Random(); + + boolean client=false; + + short listenPort; + + TunManager tcpManager=null; + + CapEnv capEnv; + + Thread versinMonThread; + + boolean detect_by_tcp=true; + + public boolean tcpEnable=false; + + public boolean fwSuccess=true; + + boolean ppp=false; + + { + capEnv=this; + } + + public CapEnv(boolean isClient,boolean fwSuccess){ + this.client=isClient; + this.fwSuccess=fwSuccess; + tcpManager=new TunManager(this); + } + + public void init() throws Exception{ + initInterface(); + Thread thread_process=new Thread(){ + + public void run(){ + while(true){ + try { + Packet packet=packetList.take(); + EthernetPacket packet_eth=(EthernetPacket) packet; + EthernetHeader head_eth=packet_eth.getHeader(); + + IpV4Packet ipV4Packet=null; + if(ppp){ + ipV4Packet=getIpV4Packet_pppoe(packet_eth); + }else { + if(packet_eth.getPayload() instanceof IpV4Packet){ + ipV4Packet=(IpV4Packet) packet_eth.getPayload(); + } + } + if(ipV4Packet!=null){ + IpV4Header ipV4Header=ipV4Packet.getHeader(); + if(ipV4Packet.getPayload() instanceof TcpPacket){ + TcpPacket tcpPacket=(TcpPacket) ipV4Packet.getPayload(); + TcpHeader tcpHeader=tcpPacket.getHeader(); + if(client){ + TCPTun conn=tcpManager.getTcpConnection_Client(ipV4Header.getSrcAddr().getHostAddress(),tcpHeader.getSrcPort().value(), tcpHeader.getDstPort().value()); + if(conn!=null){ + conn.process_client(capEnv,packet,head_eth,ipV4Header,tcpPacket,false); + } + }else { + TCPTun conn=null;conn = tcpManager.getTcpConnection_Server(ipV4Header.getSrcAddr().getHostAddress(),tcpHeader.getSrcPort().value()); + if( + tcpHeader.getDstPort().value()==listenPort){ + if(tcpHeader.getSyn()&&!tcpHeader.getAck()&&conn==null){ + conn=new TCPTun(capEnv,ipV4Header.getSrcAddr(),tcpHeader.getSrcPort().value()); + tcpManager.addConnection_Server(conn); + } + conn = tcpManager.getTcpConnection_Server(ipV4Header.getSrcAddr().getHostAddress(),tcpHeader.getSrcPort().value()); + if(conn!=null){ + conn.process_server(packet,head_eth,ipV4Header,tcpPacket,true); + } + } + } + }else if(packet_eth.getPayload() instanceof IllegalPacket){ + MLog.println("IllegalPacket!!!"); + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (IllegalRawDataException e) { + e.printStackTrace(); + } + } + } + + }; + thread_process.start(); + + + + Thread systemSleepScanThread=new Thread(){ + public void run(){ + long t=System.currentTimeMillis(); + while(true){ + if(System.currentTimeMillis()-t>5*1000){ + for(int i=0;i<10;i++){ + MLog.info("休眠恢复... "+(i+1)); + try { + boolean success=initInterface(); + if(success){ + MLog.info("休眠恢复成功 "+(i+1)); + break; + } + } catch (Exception e1) { + e1.printStackTrace(); + } + + try { + Thread.sleep(5*1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + t=System.currentTimeMillis(); + try { + Thread.sleep(1*1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + systemSleepScanThread.start(); + } + + PromiscuousMode getMode(PcapNetworkInterface pi){ + PromiscuousMode mode=null; + String string=(pi.getDescription()+":"+pi.getName()).toLowerCase(); + if(string.contains("wireless")){ + mode= PromiscuousMode.NONPROMISCUOUS; + }else { + mode= PromiscuousMode.PROMISCUOUS; + } + return mode; + } + + boolean initInterface() throws Exception{ + boolean success=false; + detectInterface(); + List allDevs = Pcaps.findAllDevs(); + MLog.println("Network Interface List: "); + for(PcapNetworkInterface pi:allDevs){ + String desString=""; + if(pi.getDescription()!=null){ + desString=pi.getDescription(); + } + MLog.info(" "+desString+" "+pi.getName()); + if(pi.getName().equals(selectedInterfaceName) + &&desString.equals(selectedInterfaceDes)){ + nif=pi; + //break; + } + } + if(nif!=null){ + String desString=""; + if(nif.getDescription()!=null){ + desString=nif.getDescription(); + } + success=true; + MLog.info("Selected Network Interface:\n"+" "+desString+" "+nif.getName()); + if(fwSuccess){ + tcpEnable=true; + } + }else { + tcpEnable=false; + MLog.info("Select Network Interface failed,can't use TCP protocal!\n"); + } + if(tcpEnable){ + sendHandle = nif.openLive(SNAPLEN,getMode(nif), READ_TIMEOUT); + final PcapHandle handle= nif.openLive(SNAPLEN, getMode(nif), READ_TIMEOUT); + + final PacketListener listener= new PacketListener() { + @Override + public void gotPacket(Packet packet) { + + try { + if(packet instanceof EthernetPacket){ + packetList.add(packet); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + }; + + Thread thread=new Thread(){ + + public void run(){ + try { + handle.loop(COUNT, listener); + PcapStat ps = handle.getStats(); + handle.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + }; + thread.start(); + } + + if(!client){ + MLog.info("FinalSpeed server start success."); + } + return success; + + } + + void detectInterface() { + List allDevs = null; + HashMap handleTable=new HashMap(); + try { + allDevs = Pcaps.findAllDevs(); + } catch (PcapNativeException e1) { + e1.printStackTrace(); + return; + } + for(final PcapNetworkInterface pi:allDevs){ + try { + final PcapHandle handle = pi.openLive(SNAPLEN, getMode(pi), READ_TIMEOUT); + handleTable.put(pi, handle); + final PacketListener listener= new PacketListener() { + @Override + public void gotPacket(Packet packet) { + + try { + if(packet instanceof EthernetPacket){ + EthernetPacket packet_eth=(EthernetPacket) packet; + EthernetHeader head_eth=packet_eth.getHeader(); + + if(head_eth.getType().value()==0xffff8864){ + ppp=true; + PacketUtils.ppp=ppp; + } + + IpV4Packet ipV4Packet=null; + IpV4Header ipV4Header=null; + + if(ppp){ + ipV4Packet=getIpV4Packet_pppoe(packet_eth); + }else { + if(packet_eth.getPayload() instanceof IpV4Packet){ + ipV4Packet=(IpV4Packet) packet_eth.getPayload(); + } + } + if(ipV4Packet!=null){ + ipV4Header=ipV4Packet.getHeader(); + + if(ipV4Header.getSrcAddr().getHostAddress().equals(testIp_tcp)){ + local_mac=head_eth.getDstAddr(); + gateway_mac=head_eth.getSrcAddr(); + local_ipv4=ipV4Header.getDstAddr(); + selectedInterfaceName=pi.getName(); + if(pi.getDescription()!=null){ + selectedInterfaceDes=pi.getDescription(); + } + //MLog.println("local_mac_tcp1 "+gateway_mac+" gateway_mac "+gateway_mac+" local_ipv4 "+local_ipv4); + } + if(ipV4Header.getDstAddr().getHostAddress().equals(testIp_tcp)){ + local_mac=head_eth.getSrcAddr(); + gateway_mac=head_eth.getDstAddr(); + local_ipv4=ipV4Header.getSrcAddr(); + selectedInterfaceName=pi.getName(); + if(pi.getDescription()!=null){ + selectedInterfaceDes=pi.getDescription(); + } + //MLog.println("local_mac_tcp2 local_mac "+local_mac+" gateway_mac "+gateway_mac+" local_ipv4 "+local_ipv4); + } + //udp + if(ipV4Header.getDstAddr().getHostAddress().equals(testIp_udp)){ + local_mac=head_eth.getSrcAddr(); + gateway_mac=head_eth.getDstAddr(); + local_ipv4=ipV4Header.getSrcAddr(); + selectedInterfaceName=pi.getName(); + if(pi.getDescription()!=null){ + selectedInterfaceDes=pi.getDescription(); + } + //MLog.println("local_mac_udp "+gateway_mac+" gateway_mac"+gateway_mac+" local_ipv4 "+local_ipv4); + } + + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + }; + + Thread thread=new Thread(){ + + public void run(){ + try { + handle.loop(COUNT, listener); + PcapStat ps = handle.getStats(); + handle.close(); + } catch (Exception e) { + //e.printStackTrace(); + } + } + + }; + thread.start(); + } catch (PcapNativeException e1) { + + } + + } + + //detectMac_udp(); + try { + detectMac_tcp(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + + Iterator it=handleTable.keySet().iterator(); + while(it.hasNext()){ + PcapNetworkInterface pi=it.next(); + PcapHandle handle=handleTable.get(pi); + try { + handle.breakLoop(); + } catch (NotOpenException e) { + e.printStackTrace(); + } + //handle.close();//linux下会阻塞 + } + } + + IpV4Packet getIpV4Packet_pppoe(EthernetPacket packet_eth) throws IllegalRawDataException { + IpV4Packet ipV4Packet=null; + byte[] pppData=packet_eth.getPayload().getRawData(); + if(pppData.length>8&&pppData[8]==0x45){ + byte[] b2=new byte[2]; + System.arraycopy(pppData, 4, b2, 0, 2); + short len=(short) ByteShortConvert.toShort(b2, 0); + int ipLength=toUnsigned(len)-2; + byte[] ipData=new byte[ipLength]; + //设置ppp参数 + PacketUtils.pppHead_static[2]=pppData[2]; + PacketUtils.pppHead_static[3]=pppData[3]; + if(ipLength==(pppData.length-8)){ + System.arraycopy(pppData, 8, ipData, 0, ipLength); + ipV4Packet= IpV4Packet.newPacket(ipData, 0, ipData.length); + }else { + MLog.println("长度不符!"); + } + } + return ipV4Packet; + } + + + + public static String printHexString(byte[] b) { + StringBuffer sb=new StringBuffer(); + for (int i = 0; i < b.length; i++) + { + String hex = Integer.toHexString(b[i] & 0xFF); + hex= hex.replaceAll(":", " "); + if (hex.length() == 1) + { + hex = '0' + hex; + } + sb.append(hex + " "); + } + return sb.toString(); + } + + public void createTcpTun_Client(String dstAddress,short dstPort) throws Exception{ + Inet4Address serverAddress=(Inet4Address) Inet4Address.getByName(dstAddress); + TCPTun conn=new TCPTun(this,serverAddress,dstPort,local_mac,gateway_mac); + tcpManager.addConnection_Client(conn); + boolean success=false; + for(int i=0;i<6;i++){ + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if(conn.preDataReady){ + success=true; + break; + } + } + if(success){ + tcpManager.setDefaultTcpTun(conn); + }else { + tcpManager.removeTun(conn); + tcpManager.setDefaultTcpTun(null); + throw new Exception("创建隧道失败!"); + } + } + + private void detectMac_tcp() throws UnknownHostException{ + InetAddress address=InetAddress.getByName("www.bing.com"); + final int por=80; + testIp_tcp=address.getHostAddress(); + for(int i=0;i<5;i++){ + try { + Route.es.execute(new Runnable() { + + @Override + public void run() { + try { + Socket socket=new Socket(testIp_tcp,por); + socket.close(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + Thread.sleep(500); + if(local_mac!=null){ + break; + } + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + } + } + + private void detectMac_udp(){ + for(int i=0;i<10;i++){ + try { + DatagramSocket ds=new DatagramSocket(); + DatagramPacket dp=new DatagramPacket(new byte[1000], 1000); + dp.setAddress(InetAddress.getByName(testIp_udp)); + dp.setPort(5555); + ds.send(dp); + ds.close(); + Thread.sleep(500); + if(local_mac!=null){ + break; + } + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + } + + } + + public short getListenPort() { + return listenPort; + } + + public void setListenPort(short listenPort) { + this.listenPort = listenPort; + if(!client){ + MLog.info("Listen tcp port: "+toUnsigned(listenPort)); + } + } + + public static int toUnsigned(short s) { + return s & 0x0FFFF; + } + +} diff --git a/src/main/java/net/fs/cap/CapServer.java b/src/main/java/net/fs/cap/CapServer.java new file mode 100755 index 0000000..37161f1 --- /dev/null +++ b/src/main/java/net/fs/cap/CapServer.java @@ -0,0 +1,18 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + + +public class CapServer { + + CapServer(){ + CapEnv capEnv=null; + try { + capEnv=new CapEnv(false,true); + capEnv.init(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/net/fs/cap/CustomTcpSackOption.java b/src/main/java/net/fs/cap/CustomTcpSackOption.java new file mode 100755 index 0000000..188c641 --- /dev/null +++ b/src/main/java/net/fs/cap/CustomTcpSackOption.java @@ -0,0 +1,375 @@ +/*_########################################################################## + _## + _## Copyright (C) 2014 Pcap4J.org + _## + _########################################################################## +*/ + +package net.fs.cap; + +import org.pcap4j.packet.IllegalRawDataException; +import org.pcap4j.packet.LengthBuilder; +import org.pcap4j.packet.TcpPacket.TcpOption; +import org.pcap4j.packet.namednumber.TcpOptionKind; +import org.pcap4j.util.ByteArrays; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import static org.pcap4j.util.ByteArrays.INT_SIZE_IN_BYTES; + +/** + * @author Kaito Yamada + * @since pcap4j 1.2.0 + */ +public final class CustomTcpSackOption implements TcpOption { + + /* + * http://tools.ietf.org/html/rfc2018 + * + * +--------+--------+ + * | Kind=5 | Length | + * +--------+--------+--------+--------+ + * | Left Edge of 1st Block | + * +--------+--------+--------+--------+ + * | Right Edge of 1st Block | + * +--------+--------+--------+--------+ + * | | + * / . . . / + * | | + * +--------+--------+--------+--------+ + * | Left Edge of nth Block | + * +--------+--------+--------+--------+ + * | Right Edge of nth Block | + * +--------+--------+--------+--------+ + */ + + /** + * + */ + private static final long serialVersionUID = -3308738405807657257L; + + private final TcpOptionKind kind = TcpOptionKind.SACK; + private final byte length; + private final List sacks = new ArrayList(); + + /** + * A static factory method. + * This method validates the arguments by {@link ByteArrays#validateBounds(byte[], int, int)}, + * which may throw exceptions undocumented here. + * + * @param rawData rawData + * @param offset offset + * @param length length + * @return a new TcpSackOption object. + * @throws IllegalRawDataException if parsing the raw data fails. + */ + public static CustomTcpSackOption newInstance( + byte[] rawData, int offset, int length + ) throws IllegalRawDataException { + ByteArrays.validateBounds(rawData, offset, length); + return new CustomTcpSackOption(rawData, offset, length); + } + + private CustomTcpSackOption(byte[] rawData, int offset, int length) throws IllegalRawDataException { + if (length < 2) { + StringBuilder sb = new StringBuilder(50); + sb.append("The raw data length must be more than 1. rawData: ") + .append(ByteArrays.toHexString(rawData, " ")) + .append(", offset: ") + .append(offset) + .append(", length: ") + .append(length); + throw new IllegalRawDataException(sb.toString()); + } + if (rawData[offset] != kind.value()) { + StringBuilder sb = new StringBuilder(100); + sb.append("The kind must be: ") + .append(kind.valueAsString()) + .append(" rawData: ") + .append(ByteArrays.toHexString(rawData, " ")) + .append(", offset: ") + .append(offset) + .append(", length: ") + .append(length); + throw new IllegalRawDataException(sb.toString()); + } + + this.length = rawData[1 + offset]; + int lengthFieldAsInt = getLengthAsInt(); + if (lengthFieldAsInt < 2) { + throw new IllegalRawDataException( + "The value of length field must be more than 1 but: " + lengthFieldAsInt + ); + } + + if ((lengthFieldAsInt - 2) % (INT_SIZE_IN_BYTES * 2) != 0) { + StringBuilder sb = new StringBuilder(100); + sb.append( + "The value of length field must be an integer multiple of 8 octets long but: " + ) + .append(lengthFieldAsInt); + throw new IllegalRawDataException(sb.toString()); + } + if (length < lengthFieldAsInt) { + StringBuilder sb = new StringBuilder(100); + sb.append("rawData is too short. length field: ") + .append(lengthFieldAsInt) + .append(", rawData: ") + .append(ByteArrays.toHexString(rawData, " ")) + .append(", offset: ") + .append(offset) + .append(", length: ") + .append(length); + throw new IllegalRawDataException(sb.toString()); + } + + for (int i = 2; i < lengthFieldAsInt; i += INT_SIZE_IN_BYTES * 2) { + sacks.add( + new Sack( + ByteArrays.getInt(rawData, i + offset), + ByteArrays.getInt(rawData, i + INT_SIZE_IN_BYTES + offset) + ) + ); + } + } + + private CustomTcpSackOption(Builder builder) { + if ( + builder == null + || builder.sacks == null + ) { + StringBuilder sb = new StringBuilder(); + sb.append("builder: ").append(builder) + .append(" builder.sacks: ").append(builder.sacks); + throw new NullPointerException(sb.toString()); + } + + this.sacks.addAll(builder.sacks); + + if (builder.correctLengthAtBuild) { + this.length = (byte)length(); + } + else { + this.length = builder.length; + } + } + + @Override + public TcpOptionKind getKind() { + return kind; + } + + /** + * + * @return length + */ + public byte getLength() { return length; } + + /** + * + * @return length + */ + public int getLengthAsInt() { return 0xFF & length; } + + @Override + public int length() { + return sacks.size() * INT_SIZE_IN_BYTES * 2 + 2; + } + + @Override + public byte[] getRawData() { + byte[] rawData = new byte[length()]; + rawData[0] = kind.value(); + rawData[1] = length; + + int offset = 2; + for (Sack sack: sacks) { + System.arraycopy( + ByteArrays.toByteArray(sack.leftEdge), 0, + rawData, offset, INT_SIZE_IN_BYTES + ); + System.arraycopy( + ByteArrays.toByteArray(sack.rightEdge), 0, + rawData, offset + INT_SIZE_IN_BYTES, INT_SIZE_IN_BYTES + ); + offset += INT_SIZE_IN_BYTES * 2; + } + + return rawData; + } + + /** + * + * @return a new Builder object populated with this object's fields. + */ + public Builder getBuilder() { + return new Builder(this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[Kind: ") + .append(kind); + sb.append("] [Length: ") + .append(getLengthAsInt()) + .append(" bytes]"); + for (Sack sack: sacks) { + sb.append(" [LE: ") + .append(sack.getLeftEdgeAsLong()) + .append(" RE: ") + .append(sack.getRightEdgeAsLong()) + .append("]"); + } + return sb.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { return true; } + if (!this.getClass().isInstance(obj)) { return false; } + + CustomTcpSackOption other = (CustomTcpSackOption)obj; + return + length == other.length + && sacks.equals(other.sacks); + } + + public List getSacks() { + return sacks; +} + +@Override + public int hashCode() { + int result = 17; + result = 31 * result + length; + result = 31 * result + sacks.hashCode(); + return result; + } + + /** + * @author Kaito Yamada + * @since pcap4j 1.2.0 + */ + public static final class Builder + implements LengthBuilder { + + private byte length; + private boolean correctLengthAtBuild; + private List sacks; + + /** + * + */ + public Builder() {} + + private Builder(CustomTcpSackOption option) { + this.length = option.length; + } + + /** + * @param length length + * @return this Builder object for method chaining. + */ + public Builder length(byte length) { + this.length = length; + return this; + } + + /** + * @param sacks sacks + * @return this Builder object for method chaining. + */ + public Builder sacks(List sacks) { + this.sacks = sacks; + return this; + } + + @Override + public Builder correctLengthAtBuild(boolean correctLengthAtBuild) { + this.correctLengthAtBuild = correctLengthAtBuild; + return this; + } + + @Override + public CustomTcpSackOption build() { + return new CustomTcpSackOption(this); + } + + } + + /** + * @author Kaito Yamada + * @since pcap4j 1.2.0 + */ + public static final class Sack implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1218420566089129438L; + + private final int leftEdge; + private final int rightEdge; + + /** + * @param leftEdge leftEdge + * @param rightEdge rightEdge + */ + public Sack(int leftEdge, int rightEdge) { + this.leftEdge = leftEdge; + this.rightEdge = rightEdge; + } + + /** + * @return leftEdge + */ + public int getLeftEdge() { + return leftEdge; + } + + /** + * @return leftEdge + */ + public long getLeftEdgeAsLong() { + return 0xFFFFFFFFL & leftEdge; + } + + /** + * @return rightEdge + */ + public int getRightEdge() { + return rightEdge; + } + + /** + * @return rightEdge + */ + public long getRightEdgeAsLong() { + return 0xFFFFFFFFL & rightEdge; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { return true; } + if (!this.getClass().isInstance(obj)) { return false; } + + Sack other = (Sack)obj; + return + leftEdge == other.leftEdge + && rightEdge == other.rightEdge; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + leftEdge; + result = 31 * result + rightEdge; + return result; + } + + } + +} diff --git a/src/main/java/net/fs/cap/IPacket.java b/src/main/java/net/fs/cap/IPacket.java new file mode 100755 index 0000000..1777715 --- /dev/null +++ b/src/main/java/net/fs/cap/IPacket.java @@ -0,0 +1,23 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +import org.pcap4j.packet.Packet; + +public class IPacket { + + int index; + + int sequence; + + int legth; + + Packet packet; + + long firstSendTime; + + long sendTime; + + long reSendCount; + +} diff --git a/src/main/java/net/fs/cap/PacketUtils.java b/src/main/java/net/fs/cap/PacketUtils.java new file mode 100755 index 0000000..a1331d5 --- /dev/null +++ b/src/main/java/net/fs/cap/PacketUtils.java @@ -0,0 +1,369 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +import net.fs.utils.ByteShortConvert; +import org.pcap4j.packet.*; +import org.pcap4j.packet.TcpPacket.TcpOption; +import org.pcap4j.packet.namednumber.EtherType; +import org.pcap4j.packet.namednumber.IpNumber; +import org.pcap4j.packet.namednumber.IpVersion; +import org.pcap4j.packet.namednumber.TcpPort; +import org.pcap4j.util.MacAddress; + +import java.net.Inet4Address; +import java.util.ArrayList; + +public class PacketUtils { + + static byte ttl=64; + + static short mtu=1440; + + static byte shiftCount=6; + + static short window=(short) (64*1024-1); + + public static boolean ppp=false; + + public static byte[] pppHead_static={0x11,0x00,0x44,0x44,0x00,0x44,0x00,0x21}; + + + public static Packet buildIpV4( + MacAddress srcAddress_mac, + MacAddress dstAddrress_mac, + IpV4Packet.Builder builder_ipv4){ + + org.pcap4j.packet.Packet.Builder builder=null; + EtherType etherType=null; + Packet p=null; + if(ppp){ + etherType= EtherType.PPPOE_SESSION_STAGE; + + UnknownPacket.Builder pppBuilder=new UnknownPacket.Builder(); + byte[] ipData=builder_ipv4.build().getRawData(); + + byte[] lenb=new byte[2]; + ByteShortConvert.toByteArray((short) (ipData.length+2), lenb, 0); + + byte[] pppHead=new byte[8]; + System.arraycopy(pppHead_static, 0, pppHead, 0, pppHead.length); + System.arraycopy(lenb, 0, pppHead, 4, 2); + + byte[] newData=new byte[pppHead.length+ipData.length]; + System.arraycopy(pppHead, 0, newData, 0, pppHead.length); + System.arraycopy(ipData, 0, newData, 8, ipData.length); + pppBuilder.rawData(newData); + + builder=pppBuilder; + }else { + etherType= EtherType.IPV4; + builder=builder_ipv4; + } + + EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder(); + etherBuilder.dstAddr(dstAddrress_mac) + .srcAddr(srcAddress_mac) + .type(etherType) + .payloadBuilder(builder) + .paddingAtBuild(true); + + p = etherBuilder.build(); + + return p; + } + + static Packet createDataPacket( + MacAddress srcAddress_mac, + MacAddress dstAddrress_mac, + Inet4Address srcAddress,short srcPort, + Inet4Address dstAddress,short dstPort, + int sequence,int ack, byte[] data,short ident){ + Packet p=null; + + TcpPacket.Builder builder_tcp=new TcpPacket.Builder(); + builder_tcp.payloadBuilder(new UnknownPacket.Builder().rawData(data)); + builder_tcp.correctChecksumAtBuild(true); + builder_tcp.correctLengthAtBuild(true); + builder_tcp.paddingAtBuild(true); + builder_tcp.ack(true); + builder_tcp.acknowledgmentNumber(ack); + //builder_tcp.checksum(tcpHeader.getChecksum()); + //builder_tcp.dataOffset((byte)8); + builder_tcp.dstAddr(dstAddress); + builder_tcp.dstPort(new TcpPort( dstPort,"")); + builder_tcp.fin(false); + //builder_tcp.options(tcpHeader.getOptions()); + //builder_tcp.padding(tcpHeader.getPadding()); + builder_tcp.psh(false); + builder_tcp.reserved((byte) 0); + builder_tcp.rst(false); + builder_tcp.sequenceNumber(sequence); + builder_tcp.srcAddr(srcAddress); + builder_tcp.srcPort(new TcpPort( srcPort,"")); + builder_tcp.syn(false); + builder_tcp.urg(false); + //builder_tcp.urgentPointer(tcpHeader.getUrgentPointer()); + builder_tcp.window( window); + + IpV4Packet.Builder builder_ipv4=new IpV4Packet.Builder(); + builder_ipv4.correctChecksumAtBuild(true); + builder_ipv4.correctLengthAtBuild(true); + builder_ipv4.dontFragmentFlag(true); + builder_ipv4.paddingAtBuild(true); + builder_ipv4.dstAddr(dstAddress); + builder_ipv4.fragmentOffset( (short)0); + //builder_ipv4.headerChecksum(ipV4Header.getHeaderChecksum()); + //short identification= Math.abs(random.nextInt(Short.MAX_VALUE)); + //identification=ident; + builder_ipv4.identification(ident); + builder_ipv4.ihl((byte) 5); + builder_ipv4.moreFragmentFlag(false); + //builder_ipv4.options(ipV4Header.getOptions()); + //builder_ipv4.padding(ipV4Header.getPadding()); + + builder_ipv4.protocol(IpNumber.TCP); + //builder_ipv4.reservedFlag(ipV4Header.getReservedFlag()); + builder_ipv4.srcAddr(srcAddress); + builder_ipv4.tos(IpV4Rfc1349Tos.newInstance((byte) 0)); + //builder_ipv4.totalLength( 52); + builder_ipv4.ttl(ttl); + builder_ipv4.version(IpVersion.IPV4); + builder_ipv4.payloadBuilder(builder_tcp); + + p = buildIpV4(srcAddress_mac,dstAddrress_mac,builder_ipv4); + + return p; + } + + static Packet createAck( + MacAddress srcAddress_mac, + MacAddress dstAddrress_mac, + Inet4Address srcAddress,short srcPort, + Inet4Address dstAddress,short dstPort, + int ack_sequence,int sequence,short ident){ + + TcpPacket.Builder builder_tcp=new TcpPacket.Builder(); + //builder_tcp.payloadBuilder(new UnknownPacket.Builder().rawData(new byte[0])); + builder_tcp.correctChecksumAtBuild(true); + builder_tcp.correctLengthAtBuild(true); + builder_tcp.paddingAtBuild(true); + builder_tcp.ack(true); + builder_tcp.acknowledgmentNumber(ack_sequence); + //builder_tcp.checksum(tcpHeader.getChecksum()); + //builder_tcp.dataOffset((byte) 8); + builder_tcp.dstAddr(dstAddress); + builder_tcp.dstPort(new TcpPort( dstPort,"")); + //builder_tcp.fin(tcpHeader.getFin()); + + builder_tcp.psh(false); + builder_tcp.reserved((byte) 0); + builder_tcp.rst(false); + builder_tcp.sequenceNumber(sequence); + builder_tcp.srcAddr(srcAddress); + builder_tcp.srcPort(new TcpPort( srcPort,"")); + builder_tcp.syn(false); + builder_tcp.urg(false); + //builder_tcp.urgentPointer(tcpHeader.getUrgentPointer()); + builder_tcp.window( window); + + IpV4Packet.Builder builder_ipv4=new IpV4Packet.Builder(); + builder_ipv4.correctChecksumAtBuild(true); + builder_ipv4.correctLengthAtBuild(true); + builder_ipv4.paddingAtBuild(true); + builder_ipv4.dstAddr(dstAddress); + builder_ipv4.dontFragmentFlag(true); + builder_ipv4.fragmentOffset( (short) 0); + //builder_ipv4.headerChecksum(ipV4Header.getHeaderChecksum()); + //short identification= Math.abs(random.nextInt(Short.MAX_VALUE)); + builder_ipv4.identification(ident); + builder_ipv4.ihl((byte) 5); + //builder_ipv4.moreFragmentFlag(ipV4Header.getMoreFragmentFlag()); + //builder_ipv4.options(ipV4Header.getOptions()); + //builder_ipv4.padding(ipV4Header.getPadding()); + + builder_ipv4.protocol(IpNumber.TCP); + // builder_ipv4.reservedFlag(ipV4Header.getReservedFlag()); + builder_ipv4.srcAddr(srcAddress); + builder_ipv4.tos(IpV4Rfc1349Tos.newInstance((byte) 0)); + //builder_ipv4.totalLength( 52); + builder_ipv4.ttl(ttl); + builder_ipv4.version(IpVersion.IPV4); + builder_ipv4.payloadBuilder(builder_tcp); + // + + Packet p = buildIpV4(srcAddress_mac,dstAddrress_mac,builder_ipv4); + //System.out.println("自定义确认 "+" identification "+identification+" ack_sequence "+ack_sequence+" # "+tcpPacket.getHeader()); + return p; + + } + + + static Packet createSyncAck( + MacAddress srcAddress_mac, + MacAddress dstAddrress_mac, + Inet4Address srcAddress,short srcPort, + Inet4Address dstAddress,short dstPort, + int ack_sequence,int sequence,short ident){ + + TcpPacket.Builder builder_tcp=new TcpPacket.Builder(); + //builder_tcp.payloadBuilder(new UnknownPacket.Builder().rawData(new byte[0])); + builder_tcp.correctChecksumAtBuild(true); + builder_tcp.correctLengthAtBuild(true); + builder_tcp.paddingAtBuild(true); + builder_tcp.ack(true); + builder_tcp.acknowledgmentNumber(ack_sequence); + //builder_tcp.checksum(tcpHeader.getChecksum()); + //builder_tcp.dataOffset((byte) 8); + builder_tcp.dstAddr(dstAddress); + builder_tcp.dstPort(new TcpPort(dstPort,"")); + //builder_tcp.fin(tcpHeader.getFin()); + + + ArrayList tcp_options=new ArrayList(); + + TcpNoOperationOption nop= TcpNoOperationOption.getInstance(); + + TcpMaximumSegmentSizeOption seg_option=new TcpMaximumSegmentSizeOption.Builder().maxSegSize(mtu).correctLengthAtBuild(true).build(); + tcp_options.add(seg_option); + + tcp_options.add(nop); + tcp_options.add(nop); + + TcpSackPermittedOption sack_permit_option= TcpSackPermittedOption.getInstance(); + tcp_options.add(sack_permit_option); + + tcp_options.add(nop); + + TcpWindowScaleOption win_option=new TcpWindowScaleOption.Builder().shiftCount(shiftCount).correctLengthAtBuild(true).build(); + tcp_options.add(win_option); + + builder_tcp.options(tcp_options); + + //builder_tcp.padding(tcpHeader.getPadding()); + builder_tcp.psh(false); + builder_tcp.reserved((byte) 0); + builder_tcp.rst(false); + builder_tcp.sequenceNumber(sequence); + builder_tcp.srcAddr(srcAddress); + builder_tcp.srcPort(new TcpPort(srcPort,"")); + builder_tcp.syn(true); + builder_tcp.urg(false); + //builder_tcp.urgentPointer(tcpHeader.getUrgentPointer()); + builder_tcp.window( window); + + IpV4Packet.Builder builder_ipv4=new IpV4Packet.Builder(); + builder_ipv4.correctChecksumAtBuild(true); + builder_ipv4.correctLengthAtBuild(true); + builder_ipv4.paddingAtBuild(true); + builder_ipv4.dstAddr(dstAddress); + builder_ipv4.dontFragmentFlag(true); + builder_ipv4.fragmentOffset((short)0); + //builder_ipv4.headerChecksum(ipV4Header.getHeaderChecksum()); + // short identification= Math.abs(random.nextInt(Short.MAX_VALUE)); + builder_ipv4.identification(ident); + builder_ipv4.ihl((byte) 5); + //builder_ipv4.moreFragmentFlag(ipV4Header.getMoreFragmentFlag()); + //builder_ipv4.options(ipV4Header.getOptions()); + //builder_ipv4.padding(ipV4Header.getPadding()); + + builder_ipv4.protocol(IpNumber.TCP); + // builder_ipv4.reservedFlag(ipV4Header.getReservedFlag()); + builder_ipv4.srcAddr(srcAddress); + builder_ipv4.tos(IpV4Rfc1349Tos.newInstance((byte) 0)); + //builder_ipv4.totalLength( 52); + builder_ipv4.ttl(ttl); + builder_ipv4.version(IpVersion.IPV4); + builder_ipv4.payloadBuilder(builder_tcp); + // + Packet p = buildIpV4(srcAddress_mac,dstAddrress_mac,builder_ipv4); + //System.out.println("自定义确认 "+" identification "+identification+" ack_sequence "+ack_sequence+" # "+tcpPacket.getHeader()); + return p; + + } + + static Packet createSync( + MacAddress srcAddress_mac, + MacAddress dstAddrress_mac, + Inet4Address srcAddress,short srcPort, + Inet4Address dstAddress,short dstPort, + int sequence,short ident){ + TcpPacket.Builder builder_tcp=new TcpPacket.Builder(); + //builder_tcp.payloadBuilder(new UnknownPacket.Builder().rawData(new byte[0])); + builder_tcp.correctChecksumAtBuild(true); + builder_tcp.correctLengthAtBuild(true); + builder_tcp.paddingAtBuild(true); + //builder_tcp.ack(true); + //builder_tcp.acknowledgmentNumber(ack_sequence); + //builder_tcp.checksum(tcpHeader.getChecksum()); + //builder_tcp.dataOffset((byte) 8); + builder_tcp.dstAddr(dstAddress); + builder_tcp.dstPort(new TcpPort( dstPort,"")); + //builder_tcp.fin(tcpHeader.getFin()); + + TcpNoOperationOption nop= TcpNoOperationOption.getInstance(); + + ArrayList tcp_options=new ArrayList(); + + TcpMaximumSegmentSizeOption seg_option=new TcpMaximumSegmentSizeOption.Builder().maxSegSize(mtu).correctLengthAtBuild(true).build(); + tcp_options.add(seg_option); + + tcp_options.add(nop); + + TcpWindowScaleOption win_option=new TcpWindowScaleOption.Builder().shiftCount((byte)6).correctLengthAtBuild(true).build(); + tcp_options.add(win_option); + + tcp_options.add(nop); + tcp_options.add(nop); + + TcpSackPermittedOption sack_permit_option= TcpSackPermittedOption.getInstance(); + tcp_options.add(sack_permit_option); + + builder_tcp.options(tcp_options); + + //builder_tcp.padding(tcpHeader.getPadding()); + builder_tcp.psh(false); + builder_tcp.reserved((byte) 0); + builder_tcp.rst(false); + builder_tcp.sequenceNumber(sequence); + builder_tcp.srcAddr(srcAddress); + builder_tcp.srcPort(new TcpPort( srcPort,"")); + builder_tcp.syn(true); + builder_tcp.urg(false); + //builder_tcp.urgentPointer(tcpHeader.getUrgentPointer()); + builder_tcp.window( window); + + IpV4Packet.Builder builder_ipv4=new IpV4Packet.Builder(); + builder_ipv4.correctChecksumAtBuild(true); + builder_ipv4.correctLengthAtBuild(true); + builder_ipv4.paddingAtBuild(true); + builder_ipv4.dstAddr(dstAddress); + builder_ipv4.dontFragmentFlag(true); + builder_ipv4.fragmentOffset((short)0); + //builder_ipv4.headerChecksum(ipV4Header.getHeaderChecksum()); + //short identification= Math.abs(random.nextInt(Short.MAX_VALUE)); + builder_ipv4.identification(ident); + builder_ipv4.ihl((byte) 5); + //builder_ipv4.moreFragmentFlag(ipV4Header.getMoreFragmentFlag()); + //builder_ipv4.options(ipV4Header.getOptions()); + //builder_ipv4.padding(ipV4Header.getPadding()); + + builder_ipv4.protocol(IpNumber.TCP); +// builder_ipv4.reservedFlag(ipV4Header.getReservedFlag()); + builder_ipv4.srcAddr(srcAddress); + builder_ipv4.tos(IpV4Rfc1349Tos.newInstance((byte) 0)); + //builder_ipv4.totalLength( 52); + builder_ipv4.ttl(ttl); + builder_ipv4.version(IpVersion.IPV4); + builder_ipv4.payloadBuilder(builder_tcp); +// + Packet p = buildIpV4(srcAddress_mac,dstAddrress_mac,builder_ipv4); +// IpV4Packet p4=builder_ipv4.build(); +// TcpPacket tcpPacket=builder_tcp.build(); + //selfAckTable.add(identification); + //System.out.println("自定义确认 "+" identification "+identification+" ack_sequence "+ack_sequence+" # "+tcpPacket.getHeader()); + return p; + + } + +} diff --git a/src/main/java/net/fs/cap/SendRecord.java b/src/main/java/net/fs/cap/SendRecord.java new file mode 100755 index 0000000..c22eaa3 --- /dev/null +++ b/src/main/java/net/fs/cap/SendRecord.java @@ -0,0 +1,9 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +public class SendRecord { + + int sendCount; + +} diff --git a/src/main/java/net/fs/cap/TCPTun.java b/src/main/java/net/fs/cap/TCPTun.java new file mode 100755 index 0000000..4f2b076 --- /dev/null +++ b/src/main/java/net/fs/cap/TCPTun.java @@ -0,0 +1,414 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +import net.fs.utils.MLog; +import org.pcap4j.core.NotOpenException; +import org.pcap4j.core.PcapHandle; +import org.pcap4j.core.PcapNativeException; +import org.pcap4j.packet.EthernetPacket.EthernetHeader; +import org.pcap4j.packet.IpV4Packet.IpV4Header; +import org.pcap4j.packet.Packet; +import org.pcap4j.packet.TcpPacket; +import org.pcap4j.packet.TcpPacket.TcpHeader; +import org.pcap4j.util.MacAddress; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Random; + + +public class TCPTun { + + HashMap sendedTable_server=new HashMap (); + HashMap sendedTable_history_server=new HashMap (); + + int clientSequence=Integer.MIN_VALUE; + + static Random random=new Random(); + + PcapHandle sendHandle; + + HashSet selfAckTable=new HashSet(); + + HashMap sendrecordTable=new HashMap(); + + MacAddress dstMacaAddress; + + int sequenceNum=-1; + + Thread sendThread; + + boolean sended=false; + + Packet basePacket_server; + + short baseIdent=100; + + IPacket dst_readed_packet,last_send_packet; + + int presend_server; + + ArrayList packetList=new ArrayList(); + + HashMap packetTable_l=new HashMap(); + + HashMap packetTable=new HashMap(); + + ArrayList unacked_list=new ArrayList(); + + Object syn_packetList=new Object(); + + int max_client_ack=Integer.MIN_VALUE; + + int sendIndex=0; + + long lasSetDelayTime=0; + + long lastDelay=300; + + Object syn_delay=new Object(); + + Thread resendScanThread; + + boolean connectReady=false; + + boolean preDataReady=false; + + CapEnv capEnv; + + public Inet4Address remoteAddress; + public short remotePort; + int remoteStartSequence; + int remoteSequence; + int remoteIdent; + int remoteSequence_max; + + Inet4Address localAddress; + short localPort; + int localStartSequence=random.nextInt(); + int localSequence; + int localIdent=random.nextInt(Short.MAX_VALUE-100); + + Object syn_send_data=new Object(); + + long lastSendAckTime; + + long lastReceiveDataTime; + + long createTime=System.currentTimeMillis();; + + String key; + + Object syn_ident=new Object(); + + //客户端发起 + TCPTun(CapEnv capEnv, + Inet4Address serverAddress, short serverPort, + MacAddress srcAddress_mac, MacAddress dstAddrress_mac){ + this.capEnv=capEnv; + sendHandle=capEnv.sendHandle; + this.remoteAddress=serverAddress; + this.remotePort=serverPort; + localAddress=capEnv.local_ipv4; + localPort=(short)(random.nextInt(64*1024-1-10000)+10000); + Packet syncPacket=null; + try { + syncPacket = PacketUtils.createSync(srcAddress_mac, dstAddrress_mac, localAddress, localPort,serverAddress, serverPort, localStartSequence,getIdent()); + try { + sendHandle.sendPacket(syncPacket); + localSequence=localStartSequence+1; + } catch (Exception e) { + e.printStackTrace(); + } + } catch (Exception e1) { + e1.printStackTrace(); + } + MLog.println("发送第一次握手 "+" ident "+localIdent); + MLog.println(""+syncPacket); + + } + + //服务端接收 + TCPTun(CapEnv capServerEnv, + Inet4Address remoteAddress,short remotePort){ + this.capEnv=capServerEnv; + this.remoteAddress=remoteAddress; + this.remotePort=remotePort; + sendHandle=capEnv.sendHandle; + localPort=capServerEnv.listenPort; + localAddress=capEnv.local_ipv4; + } + + void init_client(Inet4Address clientAddress,int clientPort, + Inet4Address serverAddress,int serverPort, + int client_start_sequence){ + + } + + void init_server(Inet4Address clientAddress,int clientPort, + Inet4Address serverAddress,int serverPort, + int client_start_sequence,int server_start_sequence){ + + } + + public void process_server(final Packet packet, EthernetHeader ethernetHeader, IpV4Header ipV4Header, TcpPacket tcpPacket, boolean client){ + TcpHeader tcpHeader=tcpPacket.getHeader(); + + if(!preDataReady){ + if(!connectReady){ + //第一次握手 + dstMacaAddress=ethernetHeader.getSrcAddr(); + if(tcpHeader.getSyn()&&!tcpHeader.getAck()){ + remoteStartSequence=tcpHeader.getSequenceNumber(); + remoteSequence=remoteStartSequence+1; + remoteSequence_max=remoteSequence; + MLog.println("接收第一次握手 "+remoteAddress.getHostAddress()+":"+remotePort+"->"+localAddress.getHostAddress()+":"+localPort+" ident "+ipV4Header.getIdentification()); + MLog.println(""+packet); + Packet responePacket=PacketUtils.createSyncAck( + capEnv.local_mac, + capEnv.gateway_mac, + localAddress,(short)localPort, + ipV4Header.getSrcAddr(),tcpHeader.getSrcPort().value(), + tcpHeader.getSequenceNumber()+1,localStartSequence,(short)0 + ); + try { + sendHandle.sendPacket(responePacket); + } catch (Exception e) { + e.printStackTrace(); + } + localSequence=localStartSequence+1; + MLog.println("发送第二次握手 "+capEnv.local_mac+"->"+capEnv.gateway_mac+" "+localAddress+"->"+" ident "+0); + + MLog.println(""+responePacket); + } + + if(!tcpHeader.getSyn()&&tcpHeader.getAck()){ + if(tcpPacket.getPayload()==null){ + //第三次握手,客户端确认 + if(tcpHeader.getAcknowledgmentNumber()==localSequence){ + MLog.println("接收第三次握手 "+" ident "+ipV4Header.getIdentification()); + MLog.println(packet+""); + Thread t1=new Thread(){ + public void run(){ + //startSend(basePacket_server,syc_sequence_client+1); + } + }; + //t1.start(); + connectReady=true; + } + } + //MLog.println("客户端响应preview\n "+packet); + //MLog.println("request "+tcp.ack()); + sendedTable_server.remove(tcpHeader.getAcknowledgmentNumber()); + boolean selfAck=selfAckTable.contains(ipV4Header.getIdentification()); + //MLog.println("客户端确认 "+"selfack "+selfAck+" id "+ipV4Header.getIdentification()+" ack_sequence "+tcpHeader.getAcknowledgmentNumberAsLong()+" "+sendedTable_server.size()+"ppppppp "+tcpHeader); + } + + }else { + if(tcpPacket.getPayload()!=null){ + preDataReady=true; + onReceiveDataPacket( tcpPacket, tcpHeader, ipV4Header ); + byte[] sim=getSimResponeHead(); + sendData(sim); + } + } + }else { + if(tcpPacket.getPayload()!=null){ + onReceiveDataPacket( tcpPacket, tcpHeader, ipV4Header ); + TunData td=new TunData(); + td.tun=this; + td.data=tcpPacket.getPayload().getRawData(); + capEnv.vDatagramSocket.onReceinveFromTun(td); + } + } + if(tcpHeader.getRst()){ + MLog.println("reset packet "+ipV4Header.getIdentification()+" "+tcpHeader.getSequenceNumber()+" "+remoteAddress.getHostAddress()+":"+remotePort+"->"+localAddress.getHostAddress()+":"+localPort+" "+" ident "+ipV4Header.getIdentification()); + } + + } + + public void process_client(CapEnv capEnv, final Packet packet, EthernetHeader ethernetHeader, IpV4Header ipV4Header, TcpPacket tcpPacket, boolean client){ + + TcpHeader tcpHeader=tcpPacket.getHeader(); + byte[] payload=null; + if(tcpPacket.getPayload()!=null){ + payload=tcpPacket.getPayload().getRawData(); + } + + if(!preDataReady){ + if(!connectReady){ + if(tcpHeader.getAck()&&tcpHeader.getSyn()){ + if(tcpHeader.getAcknowledgmentNumber()==(localStartSequence+1)){ + MLog.println("接收第二次握手 "+" ident "+ipV4Header.getIdentification()); + MLog.println(""+packet); + remoteStartSequence=tcpHeader.getSequenceNumber(); + remoteSequence=remoteStartSequence+1; + remoteSequence_max=remoteSequence; + Packet p3=PacketUtils.createAck(capEnv.local_mac, capEnv.gateway_mac, capEnv.local_ipv4, localPort, remoteAddress, remotePort, remoteSequence , localSequence,getIdent()); + try { + sendHandle.sendPacket(p3); + MLog.println("发送第三次握手 "+" ident "+localIdent); + MLog.println(""+p3); + connectReady=true; + + byte[] sim=getSimRequestHead(remotePort); + sendData(sim); + MLog.println("发送请求 "+" ident "+localIdent); + } catch (PcapNativeException e) { + e.printStackTrace(); + } catch (NotOpenException e) { + e.printStackTrace(); + } + } + } + }else { + if(tcpPacket.getPayload()!=null){ + preDataReady=true; + onReceiveDataPacket( tcpPacket, tcpHeader, ipV4Header ); + MLog.println("接收响应 "+" ident "+ipV4Header.getIdentification()); + } + } + + }else { + if(tcpPacket.getPayload()!=null){ + //MLog.println("客户端正式接收数据 "+capClientEnv.vDatagramSocket); + onReceiveDataPacket( tcpPacket, tcpHeader, ipV4Header ); + TunData td=new TunData(); + td.tun=this; + td.data=tcpPacket.getPayload().getRawData(); + capEnv.vDatagramSocket. + onReceinveFromTun(td); + } + } + if(tcpHeader.getRst()){ + MLog.println("reset packet "+ipV4Header.getIdentification()+" "+tcpHeader.getSequenceNumber()+" "+remoteAddress.getHostAddress()+":"+remotePort+"->"+localAddress.getHostAddress()+":"+localPort); + } + + } + + void onReceiveDataPacket(TcpPacket tcpPacket, TcpHeader tcpHeader, IpV4Header ipV4Header ){ + if(System.currentTimeMillis()-lastSendAckTime>1000){ + int rs=tcpHeader.getSequenceNumber()+tcpPacket.getPayload().getRawData().length; + if(rs>remoteSequence_max){ + remoteSequence_max=rs; + } + Packet ackPacket=PacketUtils.createAck( + capEnv.local_mac, + capEnv.gateway_mac, + localAddress,(short)localPort, + ipV4Header.getSrcAddr(),tcpHeader.getSrcPort().value(), + remoteSequence_max, localSequence,getIdent()); + try { + sendHandle.sendPacket(ackPacket); + } catch (Exception e) { + e.printStackTrace(); + + } + lastSendAckTime=System.currentTimeMillis(); + lastReceiveDataTime=System.currentTimeMillis(); + } + } + + void sendData(byte[] data){ + Packet dataPacket=PacketUtils.createDataPacket(capEnv.local_mac, + capEnv.gateway_mac, + localAddress,localPort, + remoteAddress,remotePort, + localSequence,remoteSequence_max, data, (short) getIdent()); + synchronized (syn_send_data) { + try { + sendHandle.sendPacket(dataPacket); + localSequence+=data.length; + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + + short getIdent(){ + synchronized (syn_ident) { + localIdent++; + if(localIdent>=Short.MAX_VALUE){ + localIdent=0; + } + } + return (short) localIdent; + } + + public static byte[] getSimResponeHead(){ + StringBuffer sb=new StringBuffer(); + + sb.append("HTTP/1.1 200 OK"+"\r\n"); + sb.append("Server: Apache/2.2.15 (CentOS)"+"\r\n"); + sb.append("Accept-Ranges: bytes"+"\r\n"); + sb.append("Content-Length: "+(Math.abs(random.nextInt()))+"\r\n"); + sb.append("Connection: Keep-Alive"+"\r\n"); + sb.append("Content-Type: application/octet-stream"+"\r\n"); + sb.append("\r\n"); + + String simRequest=sb.toString(); + byte[] simData=simRequest.getBytes(); + return simData; + } + + public static byte[] getSimRequestHead(int port){ + StringBuffer sb=new StringBuffer(); + String domainName=getRandomString(5+random.nextInt(10))+".com"; + sb.append("GET /"+getRandomString(8+random.nextInt(10))+"."+getRandomString(2+random.nextInt(5))+" HTTP/1.1"+"\r\n"); + sb.append("Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*"+"\r\n"); + sb.append("Accept-Language: zh-CN"+"\r\n"); + sb.append("Accept-Encoding: gzip, deflate"+"\r\n"); + sb.append("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0"+"\r\n"); + sb.append("Host: "+domainName+"\r\n"); + sb.append("Connection: Keep-Alive"+"\r\n"); + sb.append("\r\n"); + String simRequest=sb.toString(); + byte[] simData=simRequest.getBytes(); + return simData; + } + + public static String getRandomString(int length) { //length表示生成字符串的长度 + String base = "abcdefghkmnopqrstuvwxyz"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + return sb.toString(); + } + + public InetAddress getSourcrAddress() { + return localAddress; + } + + public int getSourcePort() { + return localPort; + } + + public void setSourcePort(short sourcePort) { + this.localPort = sourcePort; + } + + public boolean isConnectReady() { + return connectReady; + } + + public void setConnectReady(boolean connectReady) { + this.connectReady = connectReady; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + +} diff --git a/src/main/java/net/fs/cap/TunData.java b/src/main/java/net/fs/cap/TunData.java new file mode 100755 index 0000000..a202571 --- /dev/null +++ b/src/main/java/net/fs/cap/TunData.java @@ -0,0 +1,12 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + + +public class TunData { + + TCPTun tun; + + byte[] data; + +} diff --git a/src/main/java/net/fs/cap/TunManager.java b/src/main/java/net/fs/cap/TunManager.java new file mode 100755 index 0000000..169c222 --- /dev/null +++ b/src/main/java/net/fs/cap/TunManager.java @@ -0,0 +1,125 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +import net.fs.rudp.CopiedIterator; +import net.fs.utils.MLog; + +import java.util.HashMap; +import java.util.Iterator; + +public class TunManager { + + HashMap connTable=new HashMap(); + + static TunManager tunManager; + + { + tunManager=this; + } + + TCPTun defaultTcpTun; + + Thread scanThread; + + Object syn_scan=new Object(); + + CapEnv capEnv; + + { + scanThread=new Thread(){ + public void run(){ + while(true){ + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + scan(); + } + } + }; + scanThread.start(); + } + + TunManager(CapEnv capEnv){ + this.capEnv=capEnv; + } + + void scan(){ + Iterator it=getConnTableIterator(); + while(it.hasNext()){ + String key=it.next(); + TCPTun tun=connTable.get(key); + if(tun!=null){ + if(tun.preDataReady){ + //无数据超时 + long t=System.currentTimeMillis()-tun.lastReceiveDataTime; + if(t>6000){ + connTable.remove(key); + if(capEnv.client){ + defaultTcpTun=null; + MLog.println("tcp隧道超时"); + } + } + }else{ + //连接中超时 + if(System.currentTimeMillis()-tun.createTime>5000){ + connTable.remove(key); + } + } + } + } + } + + public void removeTun(TCPTun tun){ + connTable.remove(tun.key); + } + + Iterator getConnTableIterator(){ + Iterator it=null; + synchronized (syn_scan) { + it=new CopiedIterator(connTable.keySet().iterator()); + } + return it; + } + + public static TunManager get(){ + return tunManager; + } + + public TCPTun getTcpConnection_Client(String remoteAddress,short remotePort,short localPort){ + return connTable.get(remoteAddress+":"+remotePort+":"+localPort); + } + + public void addConnection_Client(TCPTun conn) { + synchronized (syn_scan) { + String key=conn.remoteAddress.getHostAddress()+":"+conn.remotePort+":"+conn.localPort; + //MLog.println("addConnection "+key); + conn.setKey(key); + connTable.put(key, conn); + } + } + + public TCPTun getTcpConnection_Server(String remoteAddress,short remotePort){ + return connTable.get(remoteAddress+":"+remotePort); + } + + public void addConnection_Server(TCPTun conn) { + synchronized (syn_scan) { + String key=conn.remoteAddress.getHostAddress()+":"+conn.remotePort; + //MLog.println("addConnection "+key); + conn.setKey(key); + connTable.put(key, conn); + } + } + + public TCPTun getDefaultTcpTun() { + return defaultTcpTun; + } + + public void setDefaultTcpTun(TCPTun defaultTcpTun) { + this.defaultTcpTun = defaultTcpTun; + } + +} diff --git a/src/main/java/net/fs/cap/VDatagramSocket.java b/src/main/java/net/fs/cap/VDatagramSocket.java new file mode 100755 index 0000000..7264e5b --- /dev/null +++ b/src/main/java/net/fs/cap/VDatagramSocket.java @@ -0,0 +1,129 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.cap; + +import net.fs.rudp.Route; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.util.concurrent.LinkedBlockingQueue; + +public class VDatagramSocket extends DatagramSocket{ + + boolean useTcpTun=true; + + boolean client=true; + + LinkedBlockingQueue packetList=new LinkedBlockingQueue (); + + CapEnv capEnv; + + int localPort; + + Object syn_tun=new Object(); + + boolean tunConnecting=false; + + public VDatagramSocket() throws SocketException { + + } + + public VDatagramSocket(int port) throws SocketException { + localPort=port; + } + + public int getLocalPort() { + return localPort; + } + + public void send(DatagramPacket p) throws IOException { + TCPTun tun=null; + if(client){ + tun=capEnv.tcpManager.getDefaultTcpTun(); + if(tun!=null){ + if(!tun.remoteAddress.getHostAddress().equals(p.getAddress().getHostAddress()) + ||CapEnv.toUnsigned(tun.remotePort)!=p.getPort()){ + capEnv.tcpManager.removeTun(tun); + capEnv.tcpManager.setDefaultTcpTun(null); + } + }else { + tryConnectTun_Client(p.getAddress(),(short) p.getPort()); + tun=capEnv.tcpManager.getDefaultTcpTun(); + } + }else { + tun=capEnv.tcpManager.getTcpConnection_Server(p.getAddress().getHostAddress(), (short) p.getPort()); + } + if(tun!=null){ + if(tun.preDataReady){ + tun.sendData(p.getData()); + }else{ + throw new IOException("隧道未连接!"); + } + }else{ + + throw new IOException("隧道不存在! "+" thread "+Route.es.getActiveCount()+" "+p.getAddress()+":"+p.getPort()); + } + } + + //130端口调用 + void tryConnectTun_Client(InetAddress dstAddress,short dstPort){ + synchronized (syn_tun) { + if(capEnv.tcpManager.getDefaultTcpTun()==null){ + if(tunConnecting){ + try { + syn_tun.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }else { + tunConnecting=true; + try { + capEnv.createTcpTun_Client(dstAddress.getHostAddress(), dstPort); + } catch (Exception e) { + e.printStackTrace(); + } + tunConnecting=false; + } + } + } + } + + + public synchronized void receive(DatagramPacket p) throws IOException { + TunData td=null; + try { + td=packetList.take(); + p.setData(td.data); + p.setLength(td.data.length); + p.setAddress(td.tun.remoteAddress); + p.setPort(CapEnv.toUnsigned(td.tun.remotePort)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + void onReceinveFromTun(TunData td){ + packetList.add(td); + } + + public boolean isClient() { + return client; + } + + public void setClient(boolean client) { + this.client = client; + } + + public CapEnv getCapEnv() { + return capEnv; + } + + public void setCapEnv(CapEnv capEnv) { + this.capEnv = capEnv; + capEnv.vDatagramSocket=this; + } + +} diff --git a/src/main/java/net/fs/client/AddMapFrame.java b/src/main/java/net/fs/client/AddMapFrame.java new file mode 100755 index 0000000..44aa20d --- /dev/null +++ b/src/main/java/net/fs/client/AddMapFrame.java @@ -0,0 +1,156 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class AddMapFrame extends JDialog{ + + private static final long serialVersionUID = -3248779355079724594L; + + ClientUI ui; + + JTextField portTextField, text_port,nameTextField; + + int downloadSpeed,uploadSpeed; + + MapRule maprule_origin; + + boolean edit=false; + + AddMapFrame(final ClientUI ui,JFrame parent,final MapRule maprule_origin,final boolean edit){ + super(parent, ModalityType.APPLICATION_MODAL); + this.ui=ui; + this.edit=edit; + this.maprule_origin=maprule_origin; + setTitle("增加映射"); + //setSize(size); + if(edit){ + setTitle("编辑映射"); + } + + JPanel panel=(JPanel) getContentPane(); + panel.setLayout(new MigLayout("alignx center,aligny center,insets 10 10 10 10")); + + + String text="" + + "单位Mb ( 1Mb=128KB,10Mb=1280KB )
" + + ""+"请正确输入,该值会直接影响加速效果.
"; + + JPanel p3=new JPanel(); + panel.add(p3,"wrap"); + p3.setBorder(BorderFactory.createEtchedBorder()); + p3.setLayout(new MigLayout("inset 5 5 5 5")); + + p3.add(new JLabel("名称:")); + nameTextField=new JTextField(); + p3.add(nameTextField,"width :100: ,wrap"); + + p3.add(new JLabel("远程端口:")); + portTextField=new JTextField(""); + p3.add(portTextField,"width :50:,wrap"); + portTextField.setToolTipText("需要加速的端口号"); + + p3.add(new JLabel("本地端口: ")); + text_port=new JTextField(); + p3.add(text_port,"width :50: ,wrap"); + + JPanel p6=new JPanel(); + panel.add(p6,"align center,wrap"); + p6.setLayout(new MigLayout("align center")); + + JButton button_ok=createButton("确定"); + p6.add(button_ok); + button_ok.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { + checkName(nameTextField.getText()); + checkPort(text_port.getText()); + checkPort(portTextField.getText()); + String name=nameTextField.getText(); + int listen_port=Integer.parseInt(text_port.getText()); + int dst_port=Integer.parseInt(portTextField.getText()); + MapRule mapRule_new=new MapRule(); + mapRule_new.setName(name); + mapRule_new.listen_port=listen_port; + mapRule_new.setDst_port(dst_port); + if(!edit){ + ui.mapClient.portMapManager.addMapRule(mapRule_new); + }else { + ui.mapClient.portMapManager.updateMapRule(maprule_origin,mapRule_new); + } + ui.loadMapRule(); + ui.select(mapRule_new.name); + setVisible(false); + } catch (Exception e1) { + //e2.printStackTrace(); + JOptionPane.showMessageDialog(ui.mainFrame, e1.getMessage(),"消息",JOptionPane.WARNING_MESSAGE); + } + } + }); + + p6.add(new JLabel(" ")); + + JButton button_cancel=createButton("取消"); + p6.add(button_cancel); + button_cancel.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }); + + + if(edit){ + nameTextField.setText(maprule_origin.name); + text_port.setText(maprule_origin.listen_port+""); + portTextField.setText(maprule_origin.dst_port+""); + } + + pack(); + setLocationRelativeTo(parent); + setVisible(true); + } + + void checkName(String s) throws Exception{ + if(s.trim().equals("")){ + throw new Exception("请输入名称"); + } + } + + void checkDstAddress(String s) throws Exception{ + if(s.trim().equals("")){ + throw new Exception("请输入目标地址"); + } + } + + void checkPort(String s) throws Exception{ + int port=0; + try { + port=Integer.parseInt(s); + } catch (Exception e1) { + throw new Exception("请输入正确端口号"); + } + if(port<1|port>256*256){ + throw new Exception("请输入正确端口号"); + } + } + + JButton createButton(String name){ + JButton button=new JButton(name); + button.setMargin(new Insets(0,5,0,5)); + button.setFocusPainted(false); + return button; + } + + + +} diff --git a/src/main/java/net/fs/client/AddressCellRenderer.java b/src/main/java/net/fs/client/AddressCellRenderer.java new file mode 100755 index 0000000..dfe70e0 --- /dev/null +++ b/src/main/java/net/fs/client/AddressCellRenderer.java @@ -0,0 +1,66 @@ +package net.fs.client; + +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class AddressCellRenderer implements ListCellRenderer{ + + JPanel panel=null; + + JLabel addressLabel; + + Color color_normal=new Color(255,255,255); + + Color color_selected=new Color(210,233,255); + + JButton button_remove; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) { + if(panel==null){ + init(); + } + updateData( list, value, index, isSelected, cellHasFocus); + return panel; + } + + void init(){ + panel=new JPanel(); + panel.setLayout(new MigLayout("insets 0 5 0 0","[grow,fill]rel[right]", "[]0[]")); + panel.setOpaque(true); + panel.setBackground(color_normal); + addressLabel=new JLabel(""); + panel.add(addressLabel,""); + addressLabel.setOpaque(false); + + button_remove=new JButton("x"); + //panel.add(button_remove,"align right"); + button_remove.setOpaque(false); + button_remove.setContentAreaFilled(false); + button_remove.setBorderPainted(false); + button_remove.setMargin(new Insets(0, 10, 0, 10)); + button_remove.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + System.out.println(e); + } + }); + + } + + void updateData(JList list, Object value, int index, boolean isSelected,boolean cellHasFocus){ + addressLabel.setText(value.toString()); + if(isSelected){ + panel.setBackground(color_selected); + }else { + panel.setBackground(color_normal); + } + } + +} diff --git a/src/main/java/net/fs/client/AlignCellRenderer.java b/src/main/java/net/fs/client/AlignCellRenderer.java new file mode 100755 index 0000000..1fc3811 --- /dev/null +++ b/src/main/java/net/fs/client/AlignCellRenderer.java @@ -0,0 +1,15 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import javax.swing.table.DefaultTableCellRenderer; + +public class AlignCellRenderer extends DefaultTableCellRenderer{ + private static final long serialVersionUID = -6003599724059557606L; + + public AlignCellRenderer(int align){ + super(); + setHorizontalAlignment(align); + } + +} diff --git a/src/main/java/net/fs/client/ClientConfig.java b/src/main/java/net/fs/client/ClientConfig.java new file mode 100755 index 0000000..d640be5 --- /dev/null +++ b/src/main/java/net/fs/client/ClientConfig.java @@ -0,0 +1,137 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import java.util.ArrayList; + +public class ClientConfig { + + String serverAddress=""; + + int serverPort; + + int remotePort; + + public String getPasswordMd5_Proxy() { + return PasswordMd5_Proxy; + } + + public void setPasswordMd5_Proxy(String passwordMd5_Proxy) { + PasswordMd5_Proxy = passwordMd5_Proxy; + } + + String PasswordMd5_Proxy; + + String PasswordMd5; + + public String getPasswordMd5() { + return PasswordMd5; + } + + public void setPasswordMd5(String passwordMd5) { + PasswordMd5 = passwordMd5; + } + + int downloadSpeed,uploadSpeed; + + boolean direct_cn=true; + + int socks5Port=1083; + + String remoteAddress; + + String protocal="tcp"; + + boolean autoStart=false; + + ArrayList recentAddressList=new ArrayList(); + + public String getServerAddress() { + return serverAddress; + } + + public void setServerAddress(String serverAddress) { + this.serverAddress = serverAddress; + } + + public int getServerPort() { + return serverPort; + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + public int getRemotePort() { + return remotePort; + } + + public void setRemotePort(int remotePort) { + this.remotePort = remotePort; + } + + public boolean isDirect_cn() { + return direct_cn; + } + + public void setDirect_cn(boolean direct_cn) { + this.direct_cn = direct_cn; + } + + public int getDownloadSpeed() { + return downloadSpeed; + } + + public void setDownloadSpeed(int downloadSpeed) { + this.downloadSpeed = downloadSpeed; + } + + public int getUploadSpeed() { + return uploadSpeed; + } + + public void setUploadSpeed(int uploadSpeed) { + this.uploadSpeed = uploadSpeed; + } + + public int getSocks5Port() { + return socks5Port; + } + + public void setSocks5Port(int socks5Port) { + this.socks5Port = socks5Port; + } + + public String getRemoteAddress() { + return remoteAddress; + } + + public void setRemoteAddress(String remoteAddress) { + this.remoteAddress = remoteAddress; + } + + public String getProtocal() { + return protocal; + } + + public void setProtocal(String protocal) { + this.protocal = protocal; + } + + public boolean isAutoStart() { + return autoStart; + } + + public void setAutoStart(boolean autoStart) { + this.autoStart = autoStart; + } + + public ArrayList getRecentAddressList() { + return recentAddressList; + } + + public void setRecentAddressList(ArrayList recentAddressList) { + this.recentAddressList = recentAddressList; + } + +} diff --git a/src/main/java/net/fs/client/ClientNoUI.java b/src/main/java/net/fs/client/ClientNoUI.java new file mode 100755 index 0000000..cbe92cb --- /dev/null +++ b/src/main/java/net/fs/client/ClientNoUI.java @@ -0,0 +1,213 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import com.alibaba.fastjson.JSONObject; +import net.fs.netty.SocksServer; +import net.fs.rudp.Route; + +import javax.swing.*; +import java.awt.*; +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; + +public class ClientNoUI implements ClientUII{ + + MapClient mapClient; + + ClientConfig config; + + String configFilePath="conf/client_config.json"; + + ClientNoUI() throws Exception { + loadConfig(); + Route.localDownloadSpeed=config.downloadSpeed; + Route.localUploadSpeed=config.uploadSpeed; + + //mapClient=new MapClient(config.getSocks5Port(),false); +// mapClient.setUi(this); +// mapClient.setMapServer(config.getServerAddress(), config.getServerPort(),config.getRemotePort() ,config.getPasswordMd5(),config.getPasswordMd5_Proxy(),config.isDirect_cn(),false,""); + } + + void openUrl(String url){ + try { + Desktop.getDesktop().browse(new URI(url)); + } catch (IOException e1) { + e1.printStackTrace(); + } catch (URISyntaxException e1) { + e1.printStackTrace(); + } + } + + public void setMessage(String message){ + //MLog.info("状态: "+message); + } + + ClientConfig loadConfig(){ + ClientConfig cfg=new ClientConfig(); + if(!new File(configFilePath).exists()){ + JSONObject json=new JSONObject(); + try { + saveFile(json.toJSONString().getBytes(), configFilePath); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + String content=readFileUtf8(configFilePath); + JSONObject json= JSONObject.parseObject(content); + cfg.setServerAddress(json.getString("server_address")); + cfg.setServerPort(json.getIntValue("server_port")); + cfg.setRemotePort(json.getIntValue("remote_port")); + if(json.containsKey("direct_cn")){ + cfg.setDirect_cn(json.getBooleanValue("direct_cn")); + } + cfg.setDownloadSpeed(json.getIntValue("download_speed")); + cfg.setUploadSpeed(json.getIntValue("upload_speed")); + if(json.containsKey("socks5_port")){ + cfg.setSocks5Port(json.getIntValue("socks5_port")); + } + config=cfg; + } catch (Exception e) { + e.printStackTrace(); + } + return cfg; + } + + public static String readFileUtf8(String path) throws Exception{ + String str=null; + FileInputStream fis=null; + DataInputStream dis=null; + try { + File file=new File(path); + + int length=(int) file.length(); + byte[] data=new byte[length]; + + fis=new FileInputStream(file); + dis=new DataInputStream(fis); + dis.readFully(data); + str=new String(data,"utf-8"); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + }finally{ + if(fis!=null){ + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(dis!=null){ + try { + dis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return str; + } + + void saveFile(byte[] data,String path) throws Exception{ + FileOutputStream fos=null; + try { + fos=new FileOutputStream(path); + fos.write(data); + } catch (Exception e) { + throw e; + } finally { + if(fos!=null){ + fos.close(); + } + } + } + + public void updateUISpeed(int conn,int downloadSpeed,int uploadSpeed){ +// String string="连接数:"+conn+" 下载:"+Tools.getSizeStringKB(downloadSpeed)+"/S" +// +" 上传:"+Tools.getSizeStringKB(uploadSpeed)+"/S"; +// if(downloadSpeedField!=null){ +// downloadSpeedField.setText(string); +// } + } + + JButton createButton(String name){ + JButton button=new JButton(name); + button.setMargin(new Insets(0,5,0,5)); + button.setFocusPainted(false); + return button; + } + + + void initUI(){ + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + Font font = new Font("宋体",Font.PLAIN,12); + UIManager.put("ToolTip.font",font); + UIManager.put("Table.font",font); + UIManager.put("TableHeader.font",font); + UIManager.put("TextField.font",font); + UIManager.put("ComboBox.font",font); + UIManager.put("TextField.font",font); + UIManager.put("PasswordField.font",font); + UIManager.put("TextArea.font,font",font); + UIManager.put("TextPane.font",font); + UIManager.put("EditorPane.font",font); + UIManager.put("FormattedTextField.font",font); + UIManager.put("Button.font",font); + UIManager.put("CheckBox.font",font); + UIManager.put("RadioButton.font",font); + UIManager.put("ToggleButton.font",font); + UIManager.put("ProgressBar.font",font); + UIManager.put("DesktopIcon.font",font); + UIManager.put("TitledBorder.font",font); + UIManager.put("Label.font",font); + UIManager.put("List.font",font); + UIManager.put("TabbedPane.font",font); + UIManager.put("MenuBar.font",font); + UIManager.put("Menu.font",font); + UIManager.put("MenuItem.font",font); + UIManager.put("PopupMenu.font",font); + UIManager.put("CheckBoxMenuItem.font",font); + UIManager.put("RadioButtonMenuItem.font",font); + UIManager.put("Spinner.font",font); + UIManager.put("Tree.font",font); + UIManager.put("ToolBar.font",font); + UIManager.put("OptionPane.messageFont",font); + UIManager.put("OptionPane.buttonFont",font); + + ToolTipManager.sharedInstance().setInitialDelay(200); + } + + }); + } + + @Override + public boolean login() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean updateNode(boolean testSpeed) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isOsx_fw_pf() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isOsx_fw_ipfw() { + // TODO Auto-generated method stub + return false; + } +} diff --git a/src/main/java/net/fs/client/ClientStartNoUI.java b/src/main/java/net/fs/client/ClientStartNoUI.java new file mode 100755 index 0000000..8c203fb --- /dev/null +++ b/src/main/java/net/fs/client/ClientStartNoUI.java @@ -0,0 +1,11 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +public class ClientStartNoUI { + + public static void main(String[] args) throws Exception { + new ClientNoUI(); + } + +} diff --git a/src/main/java/net/fs/client/ClientUI.java b/src/main/java/net/fs/client/ClientUI.java new file mode 100755 index 0000000..3926850 --- /dev/null +++ b/src/main/java/net/fs/client/ClientUI.java @@ -0,0 +1,1248 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import net.fs.rudp.Route; +import net.fs.utils.LogOutputStream; +import net.fs.utils.MLog; +import net.fs.utils.StringRandom; +import net.fs.utils.Tools; +import net.miginfocom.swing.MigLayout; +import net.fs.netty.SocksServer; +import org.pcap4j.core.Pcaps; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Properties; +import java.util.StringTokenizer; + +public class ClientUI implements ClientUII, WindowListener { + + JFrame mainFrame; + + JComponent mainPanel; + + JComboBox text_serverAddress; + + MapClient mapClient; + + JLabel uploadSpeedField, downloadSpeedField, stateText; + + ClientConfig config = null; + + String configFilePath = "conf/client_config.json"; + //String configFilePath = "client_config.json"; + + String logoImg = "img/offline.png"; + + String offlineImg = "img/offline.png"; + + String name ="大爷专版"; + + private TrayIcon trayIcon; + + private SystemTray tray; + + int serverVersion = -1; + + int localVersion = 3; + + boolean checkingUpdate = false; + + String domain = ""; + + String homeUrl; + + public static ClientUI ui; + + JTextField text_ds, text_us; + + boolean ky = true; + + String errorMsg = "保存失败请检查输入信息!"; + + JButton button_site; + + MapRuleListModel model; + + public MapRuleListTable tcpMapRuleListTable; + + boolean capSuccess = false; + Exception capException = null; + boolean b1 = false; + + boolean success_firewall_windows = true; + + boolean success_firewall_osx = true; + + String systemName = null; + + public boolean osx_fw_pf = false; + + public boolean osx_fw_ipfw = false; + + public boolean isVisible = true; + + JRadioButton r_tcp, r_udp; + + String updateUrl; + + boolean min=false; + + LogFrame logFrame; + + LogOutputStream los; + + boolean tcpEnable=true; + + { + //domain = ""; + // homeUrl = ""; + //updateUrl = ""; + domain = "firsh.me"; + homeUrl = "https://firsh.me"; + //updateUrl = "http://fs.d1sm.net/finalspeed/update.properties"; + updateUrl = "conf/update.properties"; + } + + ClientUI(final boolean isVisible,boolean min) { + + this.min=min; + setVisible(isVisible); + + if(isVisible){ + los=new LogOutputStream(System.out); + System.setOut(los); + System.setErr(los); + } + + + systemName = System.getProperty("os.name").toLowerCase(); + MLog.info("System: " + systemName + " " + System.getProperty("os.version")); + ui = this; + mainFrame = new JFrame(); + mainFrame.setIconImage(Toolkit.getDefaultToolkit().getImage(logoImg)); + initUI(); + checkQuanxian(); + loadConfig(); + StringRandom title = new StringRandom().getInstance(); + mainFrame.setResizable(true); //锁定大小 + mainFrame.setTitle(title.getRandomString(16)); + mainFrame.addWindowListener(this); + mainPanel = (JPanel) mainFrame.getContentPane(); + mainPanel.setLayout(new MigLayout("align center , insets 10 10 10 10")); + mainPanel.setBorder(null); + + mainFrame.addWindowListener(new java.awt.event.WindowAdapter() { + public void windowOpened(WindowEvent evt) { + text_ds.requestFocus(); + } + }); + + JPanel centerPanel = new JPanel(); + mainPanel.add(centerPanel, "wrap"); + centerPanel.setLayout(new MigLayout("insets 0 0 0 0")); + + JPanel loginPanel = new JPanel(); + centerPanel.add(loginPanel, ""); + loginPanel.setLayout(new MigLayout("insets 0 0 0 0")); + + JLabel label_msg = new JLabel(); + label_msg.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5)); + JPanel rightPanel = new JPanel(); + rightPanel.setLayout(new MigLayout("insets 10 0 10 0")); + + centerPanel.add(rightPanel, "width :: ,top"); + + JPanel mapPanel = new JPanel(); + mapPanel.setLayout(new MigLayout("insets 0 0 0 0")); + mapPanel.setBorder(BorderFactory.createTitledBorder("加速列表")); + + rightPanel.add(mapPanel); + //隐藏 + rightPanel.setVisible(false); + + model = new MapRuleListModel(); + tcpMapRuleListTable = new MapRuleListTable(this, model); + + JScrollPane tablePanel = new JScrollPane(); + tablePanel.setViewportView(tcpMapRuleListTable); + + mapPanel.add(tablePanel, "height 50:160:1024 ,growy,width :250:,wrap"); + tablePanel.addMouseListener(new MouseListener() { + + public void mouseClicked(MouseEvent e) { + tcpMapRuleListTable.clearSelection(); + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseReleased(MouseEvent e) { + } + + }); + + + JPanel p9 = new JPanel(); + p9.setLayout(new MigLayout("insets 1 0 3 0 ")); + mapPanel.add(p9, "align center,wrap"); + JButton button_add = createButton("添加"); + p9.add(button_add); + button_add.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + AddMapFrame sf = new AddMapFrame(ui, mainFrame, null, false); + } + + }); + JButton button_edit = createButton("修改"); + p9.add(button_edit); + button_edit.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int index = tcpMapRuleListTable.getSelectedRow(); + if (index > -1) { + MapRule mapRule = model.getMapRuleAt(index); + AddMapFrame sf = new AddMapFrame(ui, mainFrame, mapRule, true); + } + } + + }); + JButton button_remove = createButton("删除"); + p9.add(button_remove); + button_remove.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + int index = tcpMapRuleListTable.getSelectedRow(); + if (index > -1) { + MapRule mapRule = model.getMapRuleAt(index); + + mapClient.portMapManager.removeMapRule(mapRule.getName()); + loadMapRule(); + } + } + + }); + + JPanel socket = new JPanel(); + socket.setLayout(new MigLayout("insets 3 0 5 2 ")); + mapPanel.add(socket, "align center,wrap"); + JButton start_ss = createButton("Socket5:1081"); + p9.add(start_ss); + start_ss.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SocksServer.getInstance().start(); + } + }); + + + JPanel pa = new JPanel(); + pa.setBorder(BorderFactory.createTitledBorder("服务器")); + pa.setLayout(new MigLayout("insets 0 0 0 0")); + loginPanel.add(pa, "growx,wrap"); + JPanel p1 = new JPanel(); + p1.setLayout(new MigLayout("insets 0 0 0 0")); + pa.add(p1, "wrap"); + p1.add(new JLabel("地址:"), "width 50::"); + text_serverAddress = new JComboBox(); + text_serverAddress.setToolTipText("主机:端口号"); + p1.add(text_serverAddress, "width 150::"); + text_serverAddress.setEditable(true); + TextComponentPopupMenu.installToComponent(text_serverAddress); + + ListCellRenderer renderer = new AddressCellRenderer(); + text_serverAddress.setRenderer(renderer); + text_serverAddress.setEditable(true); + + text_serverAddress.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + //System.out.println(text_serverAddress.getSelectedItem().toString()); + } + }); + + for(int n=0;n0){ + selectText=text_serverAddress.getModel().getElementAt(0).toString(); + } + text_serverAddress.setSelectedItem(selectText); + } + } + } + }); + + JPanel panelr = new JPanel(); + pa.add(panelr, "wrap"); + panelr.setLayout(new MigLayout("insets 0 0 0 0")); + panelr.add(new JLabel("传输协议:")); + r_tcp = new JRadioButton("TCP"); + r_tcp.setFocusPainted(false); + panelr.add(r_tcp); + r_udp = new JRadioButton("UDP"); + r_udp.setFocusPainted(false); + panelr.add(r_udp); + ButtonGroup bg = new ButtonGroup(); + bg.add(r_tcp); + bg.add(r_udp); + if (config.getProtocal().equals("udp")) { + r_udp.setSelected(true); + } else { + r_tcp.setSelected(true); + } + + + JPanel sp = new JPanel(); + sp.setBorder(BorderFactory.createTitledBorder("物理带宽")); + sp.setLayout(new MigLayout("insets 5 5 5 5")); + JPanel pa1 = new JPanel(); + sp.add(pa1, "wrap"); + pa1.setLayout(new MigLayout("insets 0 0 0 0")); + loginPanel.add(sp, "wrap"); + pa1.add(new JLabel("下载:"), "width ::"); + text_ds = new JTextField("0"); + pa1.add(text_ds, "width 80::"); + text_ds.setHorizontalAlignment(JTextField.RIGHT); + text_ds.setEditable(false); + + JButton button_set_speed = createButton("设置带宽"); + pa1.add(button_set_speed); + button_set_speed.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + SpeedSetFrame sf = new SpeedSetFrame(ui, mainFrame); + } + }); + + + JPanel pa2 = new JPanel(); + sp.add(pa2, "wrap"); + pa2.setLayout(new MigLayout("insets 0 0 0 0")); + loginPanel.add(sp, "wrap"); + pa2.add(new JLabel("上传:"), "width ::"); + text_us = new JTextField("0"); + pa2.add(text_us, "width 80::"); + text_us.setHorizontalAlignment(JTextField.RIGHT); + text_us.setEditable(false); + + + JPanel sp2 = new JPanel(); + sp2.setLayout(new MigLayout("insets 0 0 0 0")); + loginPanel.add(sp2, "align center, wrap"); + + final JCheckBox cb=new JCheckBox("开机启动",config.isAutoStart()); + sp2.add(cb, "align center"); + cb.addActionListener(new ActionListener(){ + + @Override + public void actionPerformed(ActionEvent e) { + config.setAutoStart(cb.isSelected()); + saveConfig(); + setAutoRun(config.isAutoStart()); + } + + }); + JButton button_show_log=createButton("显示日志"); + sp2.add(button_show_log,"wrap"); + button_show_log.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(logFrame==null){ + logFrame=new LogFrame(ui); + logFrame.setSize(700, 400); + logFrame.setLocationRelativeTo(null); + los.addListener(logFrame); + + if(los.getBuffer()!=null){ + logFrame.showText(los.getBuffer().toString()); + los.setBuffer(null); + } + } + logFrame.setVisible(true); + } + }); + + JPanel p4 = new JPanel(); + p4.setLayout(new MigLayout("insets 5 0 0 0 ")); + loginPanel.add(p4, "align center,wrap"); + JButton button_save = createButton("Start"); + p4.add(button_save); + + button_site = createButton("网站"); + p4.add(button_site); + button_site.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + openUrl(homeUrl); + } + }); + + JButton button_exit = createButton("退出"); + p4.add(button_exit); + button_exit.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + }); + button_save.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (config.getDownloadSpeed() == 0 || config.getUploadSpeed() == 0) { + SpeedSetFrame sf = new SpeedSetFrame(ui, mainFrame); + } + setMessage(""); + saveConfig(); + } + }); + + stateText = new JLabel(""); + mainPanel.add(stateText, "align right ,wrap"); + + downloadSpeedField = new JLabel(); + downloadSpeedField.setHorizontalAlignment(JLabel.RIGHT); + mainPanel.add(downloadSpeedField, "align right "); + + + updateUISpeed(0, 0, 0); + setMessage(" "); + + text_serverAddress.setSelectedItem(getServerAddressFromConfig()); + + if (config.getRemoteAddress() != null && !config.getRemoteAddress().equals("") && config.getRemotePort() > 0) { + String remoteAddressTxt = config.getRemoteAddress() + ":" + config.getRemotePort(); + } + + int width = 500; + if (systemName.contains("os x")) { + width = 600; + } + //mainFrame.setSize(width, 380); + + mainFrame.pack(); + + mainFrame.setLocationRelativeTo(null); + + PopupMenu trayMenu = new PopupMenu(); + tray = SystemTray.getSystemTray(); + trayIcon = new TrayIcon(Toolkit.getDefaultToolkit().getImage(offlineImg), name, trayMenu); + trayIcon.setImageAutoSize(true); + ActionListener listener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + mainFrame.toFront(); + setVisible(true); + mainFrame.setVisible(true); + } + }; + trayIcon.addActionListener(listener); + trayIcon.addMouseListener(new MouseListener() { + + public void mouseClicked(MouseEvent arg0) { + } + + public void mouseEntered(MouseEvent arg0) { + } + + public void mouseExited(MouseEvent arg0) { + } + + public void mousePressed(MouseEvent arg0) { + } + + public void mouseReleased(MouseEvent arg0) { + } + + }); + + try { + tray.add(trayIcon); + } catch (AWTException e1) { + e1.printStackTrace(); + } + MenuItem item3; + try { + item3 = new MenuItem("Exit"); + //item3 = new MenuItem("Exit"); + ActionListener al = new ActionListener() { + public void actionPerformed(ActionEvent e) { + exit(); + } + }; + item3.addActionListener(al); + trayMenu.add(item3); + + } catch (Exception e1) { + e1.printStackTrace(); + } + + + boolean tcpEnvSuccess=true; + checkFireWallOn(); + if (!success_firewall_windows) { + tcpEnvSuccess=false; + if (isVisible) { + mainFrame.setVisible(true); + JOptionPane.showMessageDialog(mainFrame, "启动windows防火墙失败,请先运行防火墙服务."); + } + MLog.println("启动windows防火墙失败,请先运行防火墙服务."); + // System.exit(0); + } + if (!success_firewall_osx) { + tcpEnvSuccess=false; + if (isVisible) { + mainFrame.setVisible(true); + JOptionPane.showMessageDialog(mainFrame, "启动ipfw/pfctl防火墙失败,请先安装."); + } + MLog.println("启动ipfw/pfctl防火墙失败,请先安装."); + //System.exit(0); + } + + Thread thread = new Thread() { + public void run() { + try { + Pcaps.findAllDevs(); + b1 = true; + } catch (Exception e3) { + e3.printStackTrace(); + + } + } + }; + thread.start(); + try { + thread.join(); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + //JOptionPane.showMessageDialog(mainFrame,System.getProperty("os.name")); + if (!b1) { + tcpEnvSuccess=false; + try { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + String msg = "启动失败,请先安装libpcap,否则无法使用tcp协议"; + if (systemName.contains("windows")) { + msg = "启动失败,请先安装winpcap,否则无法使用tcp协议"; + } + if (isVisible) { + mainFrame.setVisible(true); + JOptionPane.showMessageDialog(mainFrame, msg); + } + MLog.println(msg); + if (systemName.contains("windows")) { + try { + Process p = Runtime.getRuntime().exec("winpcap_install.exe", null); + } catch (IOException e) { + e.printStackTrace(); + } + tcpEnable=false; + //System.exit(0); + } + } + + }); + } catch (InvocationTargetException e2) { + e2.printStackTrace(); + } catch (InterruptedException e2) { + e2.printStackTrace(); + } + } + + + try { + mapClient = new MapClient(this,tcpEnvSuccess); + } catch (final Exception e1) { + e1.printStackTrace(); + capException = e1; + //System.exit(0); + } + + try { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + + if (!mapClient.route_tcp.capEnv.tcpEnable) { + if (isVisible) { + mainFrame.setVisible(true); + } + r_tcp.setEnabled(false); + r_udp.setSelected(true); + //JOptionPane.showMessageDialog(mainFrame,"无可用网络接口,只能使用udp协议."); + } + + //System.exit(0); + } + + }); + } catch (InvocationTargetException e2) { + e2.printStackTrace(); + } catch (InterruptedException e2) { + e2.printStackTrace(); + } + + mapClient.setUi(this); + + mapClient.setMapServer(config.getServerAddress(), config.getServerPort(), config.getRemotePort(), null, null, config.isDirect_cn(), config.getProtocal().equals("tcp"), + null); + + Route.es.execute(new Runnable() { + + @Override + public void run() { + checkUpdate(); + } + }); + + setSpeed(config.getDownloadSpeed(), config.getUploadSpeed()); + if (isVisible&!min) { + mainFrame.setVisible(true); + } + + loadMapRule(); + + if (config.getDownloadSpeed() == 0 || config.getUploadSpeed() == 0) { + SpeedSetFrame sf = new SpeedSetFrame(ui, mainFrame); + } + + //socket启动 + + } + + String getServerAddressFromConfig(){ + String server_addressTxt = config.getServerAddress(); + if (config.getServerAddress() != null && !config.getServerAddress().equals("")) { + if (config.getServerPort() != 150 + && config.getServerPort() != 0) { + server_addressTxt += (":" + config.getServerPort()); + } + } + return server_addressTxt; + } + + void checkFireWallOn() { + if (systemName.contains("os x")) { + String runFirewall = "ipfw"; + try { + final Process p = Runtime.getRuntime().exec(runFirewall, null); + osx_fw_ipfw = true; + } catch (IOException e) { + //e.printStackTrace(); + } + runFirewall = "pfctl"; + try { + final Process p = Runtime.getRuntime().exec(runFirewall, null); + osx_fw_pf = true; + } catch (IOException e) { + e.printStackTrace(); + } + success_firewall_osx = osx_fw_ipfw | osx_fw_pf; + } else if (systemName.contains("linux")) { + String runFirewall = "service iptables start"; + } else if (systemName.contains("windows")) { + String runFirewall = "netsh advfirewall set allprofiles state on"; + Thread standReadThread = null; + Thread errorReadThread = null; + try { + final Process p = Runtime.getRuntime().exec(runFirewall, null); + standReadThread = new Thread() { + public void run() { + InputStream is = p.getInputStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line; + try { + line = localBufferedReader.readLine(); + if (line == null) { + break; + } else { + if (line.contains("Windows")) { + success_firewall_windows = false; + } + } + } catch (IOException e) { + e.printStackTrace(); + //error(); + exit(); + break; + } + } + } + }; + standReadThread.start(); + + errorReadThread = new Thread() { + public void run() { + InputStream is = p.getErrorStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line; + try { + line = localBufferedReader.readLine(); + if (line == null) { + break; + } else { + System.out.println("error" + line); + } + } catch (IOException e) { + e.printStackTrace(); + //error(); + exit(); + break; + } + } + } + }; + errorReadThread.start(); + } catch (IOException e) { + e.printStackTrace(); + success_firewall_windows = false; + //error(); + } + + if (standReadThread != null) { + try { + standReadThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (errorReadThread != null) { + try { + errorReadThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + } + + void checkQuanxian() { + if (systemName.contains("windows")) { + boolean b = false; + File file = new File(System.getenv("WINDIR") + "\\test.file"); + System.out.println("auth : "+file.getAbsolutePath()); + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + b = file.exists(); + file.delete(); + + if (!b) { + //mainFrame.setVisible(true); + if (isVisible) { + JOptionPane.showMessageDialog(null, "请以管理员身份运行! "); + } + MLog.println("请以管理员身份运行,否则可能无法正常工作! "); + System.exit(0); + } + } + } + + void loadMapRule() { + tcpMapRuleListTable.setMapRuleList(mapClient.portMapManager.getMapList()); + } + + void select(String name) { + int index = model.getMapRuleIndex(name); + if (index > -1) { + tcpMapRuleListTable.getSelectionModel().setSelectionInterval(index, index); + } + } + + void setSpeed(int downloadSpeed, int uploadSpeed) { + config.setDownloadSpeed(downloadSpeed); + config.setUploadSpeed(uploadSpeed); + int s1 = (int) ((float) downloadSpeed * 1.1f); + text_ds.setText(" " + Tools.getSizeStringKB(s1) + "/s "); + int s2 = (int) ((float) uploadSpeed * 1.1f); + text_us.setText(" " + Tools.getSizeStringKB(s2) + "/s "); + Route.localDownloadSpeed = downloadSpeed; + Route.localUploadSpeed = config.uploadSpeed; + + saveConfig(); + } + + + void exit() { + mainFrame.setVisible(false); + System.exit(0); + } + + void openUrl(String url) { + try { + Desktop.getDesktop().browse(new URI(url)); + } catch (IOException e1) { + e1.printStackTrace(); + } catch (URISyntaxException e1) { + e1.printStackTrace(); + } + } + + public void setMessage(String message) { + stateText.setText("状态: " + message); + } + + ClientConfig loadConfig() { + ClientConfig cfg = new ClientConfig(); + if (!new File(configFilePath).exists()) { + JSONObject json = new JSONObject(); + try { + saveFile(json.toJSONString().getBytes(), configFilePath); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + String content = readFileUtf8(configFilePath); + JSONObject json = JSONObject.parseObject(content); + cfg.setServerAddress(json.getString("server_address")); + cfg.setServerPort(json.getIntValue("server_port")); + cfg.setRemotePort(json.getIntValue("remote_port")); + cfg.setRemoteAddress(json.getString("remote_address")); + if (json.containsKey("direct_cn")) { + cfg.setDirect_cn(json.getBooleanValue("direct_cn")); + } + cfg.setDownloadSpeed(json.getIntValue("download_speed")); + cfg.setUploadSpeed(json.getIntValue("upload_speed")); + if (json.containsKey("socks5_port")) { + cfg.setSocks5Port(json.getIntValue("socks5_port")); + } + if (json.containsKey("protocal")) { + cfg.setProtocal(json.getString("protocal")); + } + if (json.containsKey("auto_start")) { + cfg.setAutoStart(json.getBooleanValue("auto_start")); + } + if (json.containsKey("recent_address_list")) { + JSONArray list=json.getJSONArray("recent_address_list"); + for (int i = 0; i < list.size(); i++) { + cfg.getRecentAddressList().add(list.get(i).toString()); + } + } + + config = cfg; + } catch (Exception e) { + e.printStackTrace(); + } + return cfg; + } + + void saveConfig() { + Thread thread = new Thread() { + public void run() { + boolean success = false; + try { + int serverPort = 150; + String addressTxt =""; + if(text_serverAddress.getSelectedItem()!=null){ + addressTxt =text_serverAddress.getSelectedItem().toString(); + } + addressTxt = addressTxt.trim().replaceAll(" ", ""); + + String serverAddress = addressTxt; + if (addressTxt.startsWith("[")) { + int index = addressTxt.lastIndexOf("]:"); + if (index > 0) { + serverAddress = addressTxt.substring(0, index + 1); + String ports = addressTxt.substring(index + 2); + serverPort = Integer.parseInt(ports); + } + } else { + int index = addressTxt.lastIndexOf(":"); + if (index > 0) { + serverAddress = addressTxt.substring(0, index); + String ports = addressTxt.substring(index + 1); + serverPort = Integer.parseInt(ports); + } + } + + String protocal = "tcp"; + if (r_udp.isSelected()) { + protocal = "udp"; + } + + JSONObject json = new JSONObject(); + json.put("server_address", serverAddress); + json.put("server_port", serverPort); + json.put("download_speed", config.getDownloadSpeed()); + json.put("upload_speed", config.getUploadSpeed()); + json.put("socks5_port", config.getSocks5Port()); + json.put("protocal", protocal); + json.put("auto_start", config.isAutoStart()); + + + if(text_serverAddress.getModel().getSize()>0){ + text_serverAddress.removeItem(addressTxt); + } + text_serverAddress.insertItemAt(addressTxt, 0); + text_serverAddress.setSelectedItem(addressTxt);; + + + JSONArray recentAddressList=new JSONArray(); + + + int size=text_serverAddress.getModel().getSize(); + for(int n=0;n localVersion; + } + + public void checkUpdate() { + for (int i = 0; i < 3; i++) { + checkingUpdate = true; + try { + Properties propServer = new Properties(); + FileInputStream in = new FileInputStream(updateUrl); + propServer.load(in); + //HttpURLConnection uc = Tools.getConnection(updateUrl); + //uc.setUseCaches(false); + //InputStream in = uc.getInputStream(); + //propServer.load(in); + //propServer.getProperty("version") + serverVersion = Integer.parseInt(propServer.getProperty("version")); + break; + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(3 * 1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } finally { + checkingUpdate = false; + } + } + //this.haveNewVersion() + if (false) { + int option = JOptionPane.showConfirmDialog(mainFrame, "测试更新", "提醒", JOptionPane.WARNING_MESSAGE); + if (option == JOptionPane.YES_OPTION) { + openUrl(homeUrl); + } + } + + } + + void initUI() { + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + Font font = new Font("宋体", Font.PLAIN, 12); + UIManager.put("ToolTip.font", font); + UIManager.put("Table.font", font); + UIManager.put("TableHeader.font", font); + UIManager.put("TextField.font", font); + UIManager.put("ComboBox.font", font); + UIManager.put("TextField.font", font); + UIManager.put("PasswordField.font", font); + UIManager.put("TextArea.font,font", font); + UIManager.put("TextPane.font", font); + UIManager.put("EditorPane.font", font); + UIManager.put("FormattedTextField.font", font); + UIManager.put("Button.font", font); + UIManager.put("CheckBox.font", font); + UIManager.put("RadioButton.font", font); + UIManager.put("ToggleButton.font", font); + UIManager.put("ProgressBar.font", font); + UIManager.put("DesktopIcon.font", font); + UIManager.put("TitledBorder.font", font); + UIManager.put("Label.font", font); + UIManager.put("List.font", font); + UIManager.put("TabbedPane.font", font); + UIManager.put("MenuBar.font", font); + UIManager.put("Menu.font", font); + UIManager.put("MenuItem.font", font); + UIManager.put("PopupMenu.font", font); + UIManager.put("CheckBoxMenuItem.font", font); + UIManager.put("RadioButtonMenuItem.font", font); + UIManager.put("Spinner.font", font); + UIManager.put("Tree.font", font); + UIManager.put("ToolBar.font", font); + UIManager.put("OptionPane.messageFont", font); + UIManager.put("OptionPane.buttonFont", font); + + ToolTipManager.sharedInstance().setInitialDelay(130); + } + + }); + } + + public static void setAutoRun(boolean run) { + String s = new File(".").getAbsolutePath(); + String currentPaht = s.substring(0, s.length() - 1); + StringBuffer sb = new StringBuffer(); + StringTokenizer st = new StringTokenizer(currentPaht, "\\"); + while (st.hasMoreTokens()) { + sb.append(st.nextToken()); + sb.append("\\\\"); + } + ArrayList list = new ArrayList(); + list.add("Windows Registry Editor Version 5.00"); + String name="fsclient"; +// if(PMClientUI.mc){ +// name="wlg_mc"; +// } + if (run) { + list.add("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run]"); + list.add("\""+name+"\"=\"" + sb.toString() + "finalspeedclient.exe -min" + "\""); + } else { + list.add("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run]"); + list.add("\""+name+"\"=-"); + } + + File file = null; + try { + file = new File("import.reg"); + FileWriter fw = new FileWriter(file); + PrintWriter pw = new PrintWriter(fw); + for (int i = 0; i < list.size(); i++) { + String ss = list.get(i); + if (!ss.equals("")) { + pw.println(ss); + } + } + pw.flush(); + pw.close(); + Process p = Runtime.getRuntime().exec("regedit /s " + "import.reg"); + p.waitFor(); + } catch (Exception e1) { + // e1.printStackTrace(); + } finally { + if (file != null) { + file.delete(); + } + } + } + + @Override + public void windowOpened(WindowEvent e) { + } + + @Override + public void windowClosing(WindowEvent e) { + mainFrame.setVisible(false); + } + + @Override + public void windowClosed(WindowEvent e) { + } + + @Override + public void windowIconified(WindowEvent e) { + } + + @Override + public void windowDeiconified(WindowEvent e) { + } + + @Override + public void windowActivated(WindowEvent e) { + } + + @Override + public void windowDeactivated(WindowEvent e) { + } + + + @Override + public boolean login() { + return false; + } + + + @Override + public boolean updateNode(boolean testSpeed) { + return true; + + } + + public boolean isOsx_fw_pf() { + return osx_fw_pf; + } + + public void setOsx_fw_pf(boolean osx_fw_pf) { + this.osx_fw_pf = osx_fw_pf; + } + + public boolean isOsx_fw_ipfw() { + return osx_fw_ipfw; + } + + public void setOsx_fw_ipfw(boolean osx_fw_ipfw) { + this.osx_fw_ipfw = osx_fw_ipfw; + } + + public void setVisible(boolean visible) { + this.isVisible = visible; + } +} diff --git a/src/main/java/net/fs/client/ClientUII.java b/src/main/java/net/fs/client/ClientUII.java new file mode 100755 index 0000000..684fecd --- /dev/null +++ b/src/main/java/net/fs/client/ClientUII.java @@ -0,0 +1,20 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +public interface ClientUII { + + + void setMessage(String message); + + void updateUISpeed(int connNum, int downSpeed, int upSpeed); + + boolean login(); + + boolean updateNode(boolean testSpeed); + + boolean isOsx_fw_pf(); + + boolean isOsx_fw_ipfw(); + +} diff --git a/src/main/java/net/fs/client/FSClient.java b/src/main/java/net/fs/client/FSClient.java new file mode 100755 index 0000000..1bfbde3 --- /dev/null +++ b/src/main/java/net/fs/client/FSClient.java @@ -0,0 +1,29 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import org.apache.commons.cli.*; + +public class FSClient { + + public static void start() throws Exception{ +// SocksServer.getInstance().start();//启动netty + String[] args = new String[]{"-b"}; + CommandLineParser parser = new DefaultParser(); + Options options = new Options(); + options.addOption("b", "back", false, "有此参数则运行CLI版本"); + options.addOption("min", "minimize",false, "启动窗口最小化"); + CommandLine commandLine = null; + try { + commandLine = parser.parse(options, args); + } catch (ParseException e) { + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp("java -jar finalspeed.jar [-b/--back]", options); + System.exit(0); + } + boolean visible=!commandLine.hasOption("b"); + boolean min=commandLine.hasOption("min"); + + new ClientUI(visible,min); + } +} diff --git a/src/main/java/net/fs/client/LogFrame.java b/src/main/java/net/fs/client/LogFrame.java new file mode 100755 index 0000000..98f38c9 --- /dev/null +++ b/src/main/java/net/fs/client/LogFrame.java @@ -0,0 +1,117 @@ +package net.fs.client; + +import net.fs.utils.LogListener; +import net.fs.utils.LogOutputStream; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import javax.swing.text.BadLocationException; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class LogFrame extends JFrame implements LogListener{ + + private static final long serialVersionUID = 8642892909397273483L; + + ClientUI ui; + + JTextArea logArea; + + JScrollPane scroll; + + boolean autoScroll=true; + + final int SCROLL_BUFFER_SIZE = 1000; + + LogFrame(ClientUI ui){ + super("日志"); + this.ui=ui; + JPanel panel=(JPanel) getContentPane(); + panel.setLayout(new MigLayout("insets 5 5 5 5")); + + + logArea=new JTextArea(); + + scroll = new JScrollPane(logArea); + + panel.add(scroll,"width :10240:,height :10240: ,wrap"); + + JPanel p3=new JPanel(); + panel.add(p3,"align center,wrap"); + p3.setLayout(new MigLayout("inset 5 5 5 5")); + + final JCheckBox cb_lock=new JCheckBox("自动滚动",autoScroll); + p3.add(cb_lock,"align center"); + cb_lock.addActionListener(new ActionListener(){ + + @Override + public void actionPerformed(ActionEvent e) { + autoScroll=cb_lock.isSelected(); + } + + }); + + JButton button_clear=createButton("清空"); + p3.add(button_clear); + button_clear.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + logArea.setText(""); + } + }); + + } + + public void trunkTextArea(JTextArea txtWin){ + int numLinesToTrunk = txtWin.getLineCount() - SCROLL_BUFFER_SIZE; + if(numLinesToTrunk > 0) + { + try + { + int posOfLastLineToTrunk = txtWin.getLineEndOffset(numLinesToTrunk - 1); + txtWin.replaceRange("",0,posOfLastLineToTrunk); + } + catch (BadLocationException ex) { + ex.printStackTrace(); + } + } + } + + void showText(String text){ + logArea.append(text); + trunkTextArea(logArea); + if(autoScroll){ + JScrollBar vertical = scroll.getVerticalScrollBar(); + vertical.setValue(vertical.getMaximum() ); + } + } + + @Override + public void onAppendContent(LogOutputStream los,final String text) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + logArea.append(text); + trunkTextArea(logArea); + if(autoScroll){ + logArea.setCaretPosition(logArea.getDocument().getLength()); +// JScrollBar vertical = scroll.getVerticalScrollBar(); +// vertical.setValue(vertical.getMaximum() ); + } + } + }); + + } + + JButton createButton(String name){ + JButton button=new JButton(name); + button.setMargin(new Insets(0,5,0,5)); + button.setFocusPainted(false); + return button; + } + + +} diff --git a/src/main/java/net/fs/client/MapClient.java b/src/main/java/net/fs/client/MapClient.java new file mode 100755 index 0000000..9640995 --- /dev/null +++ b/src/main/java/net/fs/client/MapClient.java @@ -0,0 +1,466 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import net.fs.rudp.*; +import net.fs.utils.NetStatus; + +import java.io.*; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.util.HashSet; +import java.util.Random; + +public class MapClient implements Trafficlistener{ + + ConnectionProcessor imTunnelProcessor; + + Route route_udp,route_tcp; + + short routePort=45; + + ClientUII ui; + + String serverAddress=""; + + InetAddress address=null; + + int serverPort=130; + + NetStatus netStatus; + + long lastTrafficTime; + + int downloadSum=0; + + int uploadSum=0; + + Thread clientUISpeedUpdateThread; + + int connNum=0; + + HashSet processTable=new HashSet(); + + Object syn_process=new Object(); + + static MapClient mapClient; + + PortMapManager portMapManager; + + public String mapdstAddress; + + public int mapdstPort; + + static int monPort=25874; + + String systemName=System.getProperty("os.name").toLowerCase(); + + boolean useTcp=true; + + long clientId; + + Random ran=new Random(); + + boolean tcpEnable; + + MapClient(ClientUI ui,boolean tcpEnvSuccess) throws Exception { + this.ui=ui; + mapClient=this; + try { + final ServerSocket socket=new ServerSocket(monPort); + new Thread(){ + public void run(){ + try { + socket.accept(); + } catch (IOException e) { + e.printStackTrace(); + System.exit(0); + } + } + }.start(); + } catch (Exception e) { + //e.printStackTrace(); + System.exit(0); + } + try { + route_tcp = new Route(null,routePort,Route.mode_client,true,tcpEnvSuccess); + } catch (Exception e1) { + //e1.printStackTrace(); + throw e1; + } + try { + route_udp = new Route(null,routePort,Route.mode_client,false,tcpEnvSuccess); + } catch (Exception e1) { + //e1.printStackTrace(); + throw e1; + } + netStatus=new NetStatus(); + + portMapManager=new PortMapManager(this); + + clientUISpeedUpdateThread=new Thread(){ + public void run(){ + while(true){ + try { + Thread.sleep(500); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + updateUISpeed(); + } + } + }; + clientUISpeedUpdateThread.start(); + + Route.addTrafficlistener(this); + + } + + public static MapClient get(){ + return mapClient; + } + + private void updateUISpeed(){ + if(ui!=null){ + ui.updateUISpeed(connNum,netStatus.getDownSpeed(),netStatus.getUpSpeed()); + } + } + + public void setMapServer(String serverAddress,int serverPort,int remotePort,String passwordMd5,String password_proxy_Md5,boolean direct_cn,boolean tcp, + String password){ + if(this.serverAddress==null + ||!this.serverAddress.equals(serverAddress) + ||this.serverPort!=serverPort){ + + if(route_tcp.lastClientControl!=null){ + route_tcp.lastClientControl.close(); + } + + if(route_udp.lastClientControl!=null){ + route_udp.lastClientControl.close(); + } + + cleanRule(); + if(serverAddress!=null&&!serverAddress.equals("")){ + setFireWallRule(serverAddress,serverPort); + } + + } + this.serverAddress=serverAddress; + this.serverPort=serverPort; + address=null; + useTcp=tcp; + resetConnection(); + } + + + void setFireWallRule(String serverAddress,int serverPort){ + String ip; + try { + ip = InetAddress.getByName(serverAddress).getHostAddress(); + if(systemName.contains("mac os")){ + if(ui.isOsx_fw_pf ()){ + String tempPath="./pf.conf"; + File f=new File(tempPath); + File d=f.getParentFile(); + if(!d.exists()){ + d.mkdirs(); + } + if(f.exists()){ + f.delete(); + } + //必须换行结束 + String content="block drop quick proto tcp from any to "+ip+" port = "+serverPort+"\n"; + saveFile(content.getBytes(), tempPath); + + String cmd1="pfctl -d"; + runCommand(cmd1); + + String cmd2="pfctl -Rf "+f.getAbsolutePath(); + runCommand(cmd2); + + String cmd3="pfctl -e"; + runCommand(cmd3); + + //f.delete(); + }else if(ui.isOsx_fw_ipfw()){ + String cmd2="sudo ipfw add 5050 deny tcp from any to "+ip+" "+serverAddress+" out"; + runCommand(cmd2); + } + }else if(systemName.contains("linux")){ + String cmd2="iptables -t filter -A OUTPUT -d "+ip+" -p tcp --dport "+serverPort+" -j DROP -m comment --comment tcptun_fs "; + runCommand(cmd2); + }else if (systemName.contains("windows")) { + try { + if(systemName.contains("xp")||systemName.contains("2003")){ + String cmd_add1="ipseccmd -w REG -p \"tcptun_fs\" -r \"Block TCP/"+serverPort+"\" -f 0/255.255.255.255="+ip+"/255.255.255.255:"+serverPort+":tcp -n BLOCK -x "; + final Process p2 = Runtime.getRuntime().exec(cmd_add1,null); + p2.waitFor(); + }else { + String cmd_add1="netsh advfirewall firewall add rule name=tcptun_fs protocol=TCP dir=out remoteport="+serverPort+" remoteip="+ip+" action=block "; + final Process p2 = Runtime.getRuntime().exec(cmd_add1,null); + p2.waitFor(); + String cmd_add2="netsh advfirewall firewall add rule name=tcptun_fs protocol=TCP dir=in remoteport="+serverPort+" remoteip="+ip+" action=block "; + Process p3 = Runtime.getRuntime().exec(cmd_add2,null); + p3.waitFor(); + } + } catch (Exception e1) { + e1.printStackTrace(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + void saveFile(byte[] data,String path) throws Exception{ + FileOutputStream fos=null; + try { + fos=new FileOutputStream(path); + fos.write(data); + } catch (Exception e) { + throw e; + } finally { + if(fos!=null){ + fos.close(); + } + } + } + + void cleanRule(){ + if(systemName.contains("mac os")){ + cleanTcpTunRule_osx(); + }else if(systemName.contains("linux")){ + cleanTcpTunRule_linux(); + }else { + try { + if(systemName.contains("xp")||systemName.contains("2003")){ + String cmd_delete="ipseccmd -p \"tcptun_fs\" -w reg -y"; + final Process p1 = Runtime.getRuntime().exec(cmd_delete,null); + p1.waitFor(); + }else { + String cmd_delete="netsh advfirewall firewall delete rule name=tcptun_fs "; + final Process p1 = Runtime.getRuntime().exec(cmd_delete,null); + p1.waitFor(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + void cleanTcpTunRule_osx(){ + String cmd2="sudo ipfw delete 5050"; + runCommand(cmd2); + } + + + void cleanTcpTunRule_linux(){ + while(true){ + int row=getRow_linux(); + if(row>0){ + //MLog.println("删除行 "+row); + String cmd="iptables -D OUTPUT "+row; + runCommand(cmd); + }else { + break; + } + } + } + + int getRow_linux(){ + int row_delect=-1; + String cme_list_rule="iptables -L -n --line-number"; + //String [] cmd={"netsh","advfirewall set allprofiles state on"}; + Thread errorReadThread=null; + try { + final Process p = Runtime.getRuntime().exec(cme_list_rule,null); + + errorReadThread=new Thread(){ + public void run(){ + InputStream is=p.getErrorStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true){ + String line; + try { + line = localBufferedReader.readLine(); + if (line == null){ + break; + }else{ + //System.out.println("erroraaa "+line); + } + } catch (IOException e) { + e.printStackTrace(); + //error(); + break; + } + } + } + }; + errorReadThread.start(); + + + + InputStream is=p.getInputStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true){ + String line; + try { + line = localBufferedReader.readLine(); + // System.out.println("standaaa "+line); + if (line == null){ + break; + }else{ + if(line.contains("tcptun_fs")){ + int index=line.indexOf(" "); + if(index>0){ + String n=line.substring(0, index); + try { + if(row_delect<0){ + //System.out.println("standaaabbb "+line); + row_delect=Integer.parseInt(n); + } + } catch (Exception e) { + + } + } + }; + } + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + + + errorReadThread.join(); + p.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + //error(); + } + return row_delect; + } + + void resetConnection(){ + synchronized (syn_process) { + + } + } + + public void onProcessClose(ClientProcessorInterface process){ + synchronized (syn_process) { + processTable.remove(process); + } + } + + synchronized public void closeAndTryConnect_Login(boolean testSpeed){ + close(); + boolean loginOK=ui.login(); + if(loginOK){ + ui.updateNode(testSpeed); + //testPool(); + } + } + + synchronized public void closeAndTryConnect(){ + close(); + //testPool(); + } + + public void close(){ +// closeAllProxyRequest(); +// poolManage.close(); +// CSocketPool.closeAll(); + } + + public void trafficDownload(TrafficEvent event) { + ////#MLog.println("下载 "+event.getTraffic()); + netStatus.addDownload(event.getTraffic()); + lastTrafficTime=System.currentTimeMillis(); + downloadSum+=event.getTraffic(); + } + + public void trafficUpload(TrafficEvent event) { + ////#MLog.println("上传 "+event.getTraffic()); + netStatus.addUpload(event.getTraffic()); + lastTrafficTime=System.currentTimeMillis(); + uploadSum+=event.getTraffic(); + } + + static void runCommand(String command){ + Thread standReadThread=null; + Thread errorReadThread=null; + try { + final Process p = Runtime.getRuntime().exec(command,null); + standReadThread=new Thread(){ + public void run(){ + InputStream is=p.getInputStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true){ + String line; + try { + line = localBufferedReader.readLine(); + //System.out.println("stand "+line); + if (line == null){ + break; + } + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + } + }; + standReadThread.start(); + + errorReadThread=new Thread(){ + public void run(){ + InputStream is=p.getErrorStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true){ + String line; + try { + line = localBufferedReader.readLine(); + if (line == null){ + break; + }else{ + //System.out.println("error "+line); + } + } catch (IOException e) { + e.printStackTrace(); + //error(); + break; + } + } + } + }; + errorReadThread.start(); + standReadThread.join(); + errorReadThread.join(); + p.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + //error(); + } + } + + public boolean isUseTcp() { + return useTcp; + } + + public void setUseTcp(boolean useTcp) { + this.useTcp = useTcp; + } + + public ClientUII getUi() { + return ui; + } + + public void setUi(ClientUII ui) { + this.ui = ui; + } + +} diff --git a/src/main/java/net/fs/client/MapRule.java b/src/main/java/net/fs/client/MapRule.java new file mode 100755 index 0000000..01b1da9 --- /dev/null +++ b/src/main/java/net/fs/client/MapRule.java @@ -0,0 +1,49 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import java.io.Serializable; +import java.net.ServerSocket; + +public class MapRule implements Serializable{ + + /** + * + */ + private static final long serialVersionUID = -3504577683070928480L; + + int listen_port; + + int dst_port; + + String name; + + boolean using=false; + + ServerSocket serverSocket; + + public int getListen_port() { + return listen_port; + } + + public void setListen_port(int listen_port) { + this.listen_port = listen_port; + } + + public int getDst_port() { + return dst_port; + } + + public void setDst_port(int dst_port) { + this.dst_port = dst_port; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/net/fs/client/MapRuleListModel.java b/src/main/java/net/fs/client/MapRuleListModel.java new file mode 100755 index 0000000..d6756c6 --- /dev/null +++ b/src/main/java/net/fs/client/MapRuleListModel.java @@ -0,0 +1,91 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; +import java.util.List; + + +public class MapRuleListModel extends AbstractTableModel{ + + private static final long serialVersionUID = 2267856423317178816L; + + private List mapRuleList; + + String titles[] ; + + Class types[] = new Class[] {String.class, String.class, String.class,String.class, String.class, String.class}; + + MapRuleListModel(){ + mapRuleList=new ArrayList (); + titles = new String[] {""}; + } + + public void setMapRuleList(List list){ + mapRuleList.clear(); + if(list!=null){ + mapRuleList.addAll(list); + } + fireTableDataChanged(); + } + + public int getMapRuleIndex(String name){ + int index=-1; + int i=0; + for(MapRule r:mapRuleList){ + if(name.equals(r.getName())){ + index=i; + break; + } + i++; + } + return index; + } + + List getMapRuleList(){ + return mapRuleList; + } + + public MapRule getMapRuleAt(int row){ + if(row>-1&row getColumnClass(int c) { + return types[c]; + } + + + public boolean isCellEditable(int row, int col) { + boolean b=false; + if(col==0){ + b=true; + } + return false; + } +} diff --git a/src/main/java/net/fs/client/MapRuleListTable.java b/src/main/java/net/fs/client/MapRuleListTable.java new file mode 100755 index 0000000..4c1fe98 --- /dev/null +++ b/src/main/java/net/fs/client/MapRuleListTable.java @@ -0,0 +1,110 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import javax.swing.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.List; + +public class MapRuleListTable extends JTable{ + + private static final long serialVersionUID = -547936371303904463L; + + MapRuleListModel model; + + MapRuleListTable table; + + ClientUI ui; + + MapRuleListTable(ClientUI ui,final MapRuleListModel model){ + super(); + this.model=model; + this.ui=ui; + table=this; + setModel(model); + + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + setRowSorter(null); + + getColumnModel().getColumn(0).setMinWidth(30); + + MapRuleRender rr=new MapRuleRender(); + getColumnModel().getColumn(0).setCellRenderer(rr); + setRowHeight(50); + + new Thread(){ + public void run() { + while(true){ + try { + Thread.sleep(1000); + refresh(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }.start(); + + addMouseListener(new MouseListener() { + + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mousePressed(MouseEvent e) { + if(e.getButton()==MouseEvent.BUTTON3&&e.getClickCount()==1){ + int index=rowAtPoint(e.getPoint()); + int modelIndex=convertRowIndexToModel(index); + getSelectionModel().setSelectionInterval(modelIndex, modelIndex); + } + } + + @Override + public void mouseExited(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseClicked(MouseEvent e) { + if(e.getButton()==MouseEvent.BUTTON1&&e.getClickCount()==2){ + editRule(); + } + } + }); + + } + + void editRule(){ + int index=getSelectedRow(); + int modelIndex=convertRowIndexToModel(index); + MapRule mapRule=getModel().getMapRuleAt(modelIndex); + AddMapFrame sf=new AddMapFrame(ui,ui.mainFrame,mapRule,true); + //sf.setVisible(true); + } + + void refresh(){ + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + updateUI(); + } + }); + } + + public void setMapRuleList(List list){ + model.setMapRuleList(list); + } + + public MapRuleListModel getModel() { + return model; + } + + public void setModel(MapRuleListModel model) { + super.setModel(model); + this.model = model; + } + +} diff --git a/src/main/java/net/fs/client/MapRuleRender.java b/src/main/java/net/fs/client/MapRuleRender.java new file mode 100755 index 0000000..965e2ca --- /dev/null +++ b/src/main/java/net/fs/client/MapRuleRender.java @@ -0,0 +1,81 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import net.miginfocom.swing.MigLayout; +import sun.swing.DefaultLookup; + +import javax.swing.*; +import javax.swing.table.TableCellRenderer; +import java.awt.*; + +public class MapRuleRender extends JLabel implements TableCellRenderer { + + private static final long serialVersionUID = -3260748459008436510L; + + JPanel pleft,pright,p1; + + JLabel label_wan_address; + JLabel label2; + + MapRule rule; + + { + setOpaque(true); + setLayout(new MigLayout("insets 8 10 0 0")); + label_wan_address=new JLabel(); + add(label_wan_address,"width :500:,wrap"); + label_wan_address.setBackground(new Color(0f,0f,0f,0f)); + label_wan_address.setOpaque(true); + label2=new JLabel(); + add(label2,"width :500:,wrap"); + label2.setBackground(new Color(0f,0f,0f,0f)); + label2.setOpaque(true); + } + + + void update(MapRule rule,JTable table,int row){ + this.rule=rule; + int rowHeight=50; + int h=table.getRowHeight(row); + if(h!=rowHeight){ + table.setRowHeight(row, rowHeight); + } + String name=rule.getName(); + if(name==null){ + name="无"; + }else if(name.trim().equals("")){ + name="无"; + } + label_wan_address.setText("名称: "+rule.name+" 远程端口: "+rule.dst_port); + label2.setText("本地端口: "+rule.getListen_port()); + + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + Color fg = null; + Color bg = null; + JTable.DropLocation dropLocation = table.getDropLocation(); + if (dropLocation != null + && !dropLocation.isInsertRow() + && !dropLocation.isInsertColumn() + && dropLocation.getRow() == row + && dropLocation.getColumn() == column) { + + fg = DefaultLookup.getColor(this, ui, "Table.dropCellForeground"); + bg = DefaultLookup.getColor(this, ui, "Table.dropCellBackground"); + isSelected = true; + } + if (isSelected) { + setBackground(DefaultLookup.getColor(this, ui, "Table.dropCellBackground")); + } else { + setBackground( DefaultLookup.getColor(this, ui, "Table.alternateRowColor")); + } + MapRule rule=(MapRule)value; + update(rule,table,row); + return this; + } + +} diff --git a/src/main/java/net/fs/client/Pipe.java b/src/main/java/net/fs/client/Pipe.java new file mode 100755 index 0000000..648385d --- /dev/null +++ b/src/main/java/net/fs/client/Pipe.java @@ -0,0 +1,106 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import net.fs.rudp.ConnectionUDP; +import net.fs.rudp.UDPInputStream; +import net.fs.rudp.UDPOutputStream; +import net.fs.utils.MLog; + +import java.io.InputStream; +import java.io.OutputStream; + +public class Pipe { + + + int lastTime=-1; + + + boolean readed=false; + + public Pipe p2; + + byte[] pv; + + int pvl; + + int readedLength; + + String successMessage; + + int dstPort=-1; + + public void pipe(InputStream is,UDPOutputStream tos,int initSpeed,final Pipe p2) throws Exception{ + + int len=0; + byte[] buf=new byte[100*1024]; + boolean sendeda=false; + while((len=is.read(buf))>0){ + readed=true; + if(!sendeda){ + sendeda=true; + } + tos.write(buf, 0, len); + } + } + + + + void sendSleep(long startTime,int speed,int length){ + long needTime=(long) (1000f*length/speed); + long usedTime=System.currentTimeMillis()-startTime; + if(usedTime0){ + readedLength+=len; + if(!sendedb){ + pv=buf; + pvl=len; + sendedb=true; + } + if(dstPort>0){ + if(ClientUI.ui!=null){ + if(!msged){ + msged=true; + //String msg="隧道链接成功 "+dstPort+" 端口 !"; + //ClientUI.ui.setMessage(msg); + //MLog.println(msg); + } + + } + } + os.write(buf, 0, len); + if(!sended){ + sended=true; + } + } + } + + + + public int getReadedLength() { + return readedLength; + } + + + + public void setDstPort(int dstPort) { + this.dstPort = dstPort; + } + +} diff --git a/src/main/java/net/fs/client/PortMapManager.java b/src/main/java/net/fs/client/PortMapManager.java new file mode 100755 index 0000000..77dd1e6 --- /dev/null +++ b/src/main/java/net/fs/client/PortMapManager.java @@ -0,0 +1,269 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import net.fs.rudp.Route; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.HashMap; + +public class PortMapManager { + + MapClient mapClient; + + ArrayList mapList=new ArrayList(); + + HashMap mapRuleTable=new HashMap(); + + String configFilePath="conf/port_map.json"; + //String configFilePath="port_map.json"; + + PortMapManager(MapClient mapClient){ + this.mapClient=mapClient; + //listenPort(); + loadMapRule(); + } + + void addMapRule(MapRule mapRule) throws Exception{ + if(getMapRule(mapRule.name)!=null){ + throw new Exception("映射 "+mapRule.name+" 已存在,请修改名称!"); + } + ServerSocket serverSocket=null; + try { + serverSocket = new ServerSocket(mapRule.getListen_port()); + listen(serverSocket); + mapList.add(mapRule); + mapRuleTable.put(mapRule.listen_port, mapRule); + saveMapRule(); + } catch (IOException e2) { + //e2.printStackTrace(); + throw new Exception("端口 "+mapRule.getListen_port()+" 已经被占用!"); + }finally{ +// if(serverSocket!=null){ +// serverSocket.close(); +// } + } + } + + void removeMapRule(String name){ + MapRule mapRule=getMapRule(name); + if(mapRule!=null){ + mapList.remove(mapRule); + mapRuleTable.remove(mapRule.listen_port); + if(mapRule.serverSocket!=null){ + try { + mapRule.serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + try { + saveMapRule(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + void updateMapRule(MapRule mapRule_origin,MapRule mapRule_new) throws Exception{ + if(getMapRule(mapRule_new.name)!=null&&!mapRule_origin.name.equals(mapRule_new.name)){ + throw new Exception("映射 "+mapRule_new.name+" 已存在,请修改名称!"); + } + ServerSocket serverSocket=null; + if(mapRule_origin.listen_port!=mapRule_new.listen_port){ + try { + serverSocket = new ServerSocket(mapRule_new.getListen_port()); + listen(serverSocket); + mapRule_origin.using=false; + if(mapRule_origin.serverSocket!=null){ + mapRule_origin.serverSocket.close(); + } + mapRule_origin.serverSocket=serverSocket; + mapRuleTable.remove(mapRule_origin.listen_port); + mapRuleTable.put(mapRule_new.listen_port, mapRule_new); + } catch (IOException e2) { + //e2.printStackTrace(); + throw new Exception("端口 "+mapRule_new.getListen_port()+" 已经被占用!"); + }finally{ +// if(serverSocket!=null){ +// serverSocket.close(); +// } + } + } + mapRule_origin.name=mapRule_new.name; + mapRule_origin.listen_port=mapRule_new.listen_port; + mapRule_origin.dst_port=mapRule_new.dst_port; + saveMapRule(); + + } + + void saveMapRule() throws Exception{ + JSONObject json=new JSONObject(); + JSONArray json_map_list=new JSONArray(); + json.put("map_list", json_map_list); + if(mapList.size()==0){ + + } + for(MapRule r:mapList){ + JSONObject json_rule=new JSONObject(); + json_rule.put("name", r.name); + json_rule.put("listen_port", r.listen_port); + json_rule.put("dst_port", r.dst_port); + json_map_list.add(json_rule); + } + try { + saveFile(json.toJSONString().getBytes("utf-8"), configFilePath); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("保存失败!"); + } + } + + void loadMapRule(){ + String content; + JSONObject json=null; + try { + content = readFileUtf8(configFilePath); + json= JSONObject.parseObject(content); + } catch (Exception e) { + //e.printStackTrace(); + } + if(json!=null&&json.containsKey("map_list")){ + JSONArray json_map_list=json.getJSONArray("map_list"); + for(int i=0;i getMapList() { + return mapList; + } + + public void setMapList(ArrayList mapList) { + this.mapList = mapList; + } + + void listen(final ServerSocket serverSocket){ + Route.es.execute(new Runnable() { + + @Override + public void run() { + while(true){ + try { + final Socket socket=serverSocket.accept(); + Route.es.execute(new Runnable() { + + @Override + public void run() { + int listenPort=serverSocket.getLocalPort(); + MapRule mapRule=mapRuleTable.get(listenPort); + if(mapRule!=null){ + Route route=null; + if(mapClient.isUseTcp()){ + route=mapClient.route_tcp; + }else { + route=mapClient.route_udp; + } + PortMapProcess process=new PortMapProcess(mapClient,route, socket,mapClient.serverAddress,mapClient.serverPort,null, + null,mapRule.dst_port); + } + } + + }); + + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + } + }); + } + + void saveFile(byte[] data,String path) throws Exception{ + FileOutputStream fos=null; + try { + fos=new FileOutputStream(path); + fos.write(data); + } catch (Exception e) { + throw e; + } finally { + if(fos!=null){ + fos.close(); + } + } + } + + public static String readFileUtf8(String path) throws Exception{ + String str=null; + FileInputStream fis=null; + DataInputStream dis=null; + try { + File file=new File(path); + + int length=(int) file.length(); + byte[] data=new byte[length]; + + fis=new FileInputStream(file); + dis=new DataInputStream(fis); + dis.readFully(data); + str=new String(data,"utf-8"); + + } catch (Exception e) { + //e.printStackTrace(); + throw e; + }finally{ + if(fis!=null){ + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(dis!=null){ + try { + dis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return str; + } +} diff --git a/src/main/java/net/fs/client/PortMapProcess.java b/src/main/java/net/fs/client/PortMapProcess.java new file mode 100755 index 0000000..3da3ae5 --- /dev/null +++ b/src/main/java/net/fs/client/PortMapProcess.java @@ -0,0 +1,176 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import com.alibaba.fastjson.JSONObject; +import net.fs.rudp.*; +import net.fs.utils.MLog; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.util.Random; + +public class PortMapProcess implements ClientProcessorInterface{ + + Random ran=new Random(); + + UDPInputStream tis; + + UDPOutputStream tos; + + String serverAddress=""; + + int serverPort; + + ConnectionUDP conn; + + MapClient mapClient; + + public Socket srcSocket,dstSocket; + + DataInputStream srcIs=null; + DataOutputStream srcOs=null; + + boolean closed=false; + boolean success=false; + + public PortMapProcess(MapClient mapClient,Route route,final Socket srcSocket,String serverAddress2,int serverPort2,String password_proxy_md5, + String dstAddress,final int dstPort){ + this.mapClient=mapClient; + this.serverAddress=serverAddress2; + this.serverPort=serverPort2; + + this.srcSocket=srcSocket; + + try { + srcIs = new DataInputStream(srcSocket.getInputStream()); + srcOs=new DataOutputStream(srcSocket.getOutputStream()); + conn = route.getConnection(serverAddress, serverPort,null); + tis=conn.uis; + tos=conn.uos; + + JSONObject requestJson=new JSONObject(); + requestJson.put("dst_address", dstAddress); + requestJson.put("dst_port", dstPort); + byte[] requestData=requestJson.toJSONString().getBytes("utf-8"); + + tos.write(requestData, 0, requestData.length); + + + final Pipe p1=new Pipe(); + final Pipe p2=new Pipe(); + + + byte[] responeData=tis.read2(); + + String hs=new String(responeData,"utf-8"); + JSONObject responeJSon= JSONObject.parseObject(hs); + int code=responeJSon.getIntValue("code"); + String message=responeJSon.getString("message"); + String uimessage=""; + if(code==Constant.code_success){ + + Route.es.execute(new Runnable() { + + @Override + public void run() { + long t=System.currentTimeMillis(); + p2.setDstPort(dstPort); + try { + p2.pipe(tis, srcOs,1024*1024*1024,null); + }catch (Exception e) { + e.printStackTrace(); + }finally{ + close(); + if(p2.getReadedLength()==0){ + //String msg="fs服务连接成功,加速端口"+dstPort+"连接失败1"; + String msg="Speed服务报错 "+dstPort+" 连接失败!"; + MLog.println(msg); + ClientUI.ui.setMessage(msg); + } + } + } + + }); + + Route.es.execute(new Runnable() { + + @Override + public void run() { + try { + p1.pipe(srcIs, tos,200*1024,p2); + } catch (Exception e) { + //e.printStackTrace(); + }finally{ + close(); + } + } + + }); + success=true; + uimessage=("隧道连接成功"); + ClientUI.ui.setMessage(uimessage); + }else { + close(); + uimessage="隧道连接失败,端口"+dstPort+" 连接失败!"; + ClientUI.ui.setMessage(uimessage); + MLog.println(uimessage); + } + } catch (Exception e1) { + e1.printStackTrace(); + String msg="隧道连接失败!"; + ClientUI.ui.setMessage(msg); + MLog.println(msg); + } + + } + + void close(){ + if(!closed){ + closed=true; + if(srcIs!=null){ + try { + srcIs.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(srcOs!=null){ + try { + srcOs.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(tos!=null){ + tos.closeStream_Local(); + } + if(tis!=null){ + tis.closeStream_Local(); + } + if(conn!=null){ + conn.close_local(); + } + if(srcSocket!=null){ + try { + srcSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + mapClient.onProcessClose(this); + + } + } + + @Override + public void onMapClientClose() { + try { + srcSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/net/fs/client/SpeedSetFrame.java b/src/main/java/net/fs/client/SpeedSetFrame.java new file mode 100755 index 0000000..bb116e7 --- /dev/null +++ b/src/main/java/net/fs/client/SpeedSetFrame.java @@ -0,0 +1,105 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class SpeedSetFrame extends JDialog{ + + private static final long serialVersionUID = -3248779355079724594L; + + ClientUI ui; + + JTextField text_ds,text_us; + + SpeedSetFrame(final ClientUI ui,JFrame parent){ + super(parent, ModalityType.APPLICATION_MODAL); + this.ui=ui; + setTitle("设置带宽"); + + JPanel panel=(JPanel) getContentPane(); + panel.setLayout(new MigLayout("alignx center,aligny center,insets 10 10 10 10")); + + + panel.add(new JLabel("单位Mb ( 1Mb=128KB,10Mb=1280KB )"),"height ::,wrap"); + panel.add(new JLabel("请正确输入,该值会直接影响加速效果."),"height ::,wrap"); + + JPanel p5=new JPanel(); + panel.add(p5,"wrap"); + p5.setLayout(new MigLayout("")); + p5.add(new JLabel("下载带宽:")); + text_ds=new JTextField(""); + p5.add(text_ds,"width 50::"); + p5.add(new JLabel("Mb")); + + p5.add(new JLabel(" ")); + + p5.add(new JLabel("上传带宽:")); + text_us=new JTextField(""); + p5.add(text_us,"width 50::"); + //text_us.setEditable(false); + p5.add(new JLabel("Mb")); + + JPanel p6=new JPanel(); + panel.add(p6,"align center,wrap"); + p6.setLayout(new MigLayout("align center")); + + JButton button_ok=createButton("确定"); + p6.add(button_ok); + button_ok.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + String us=text_ds.getText().trim(); + String ds=text_us.getText().trim(); + try { + int d=(int) (Float.parseFloat(us)*1024*1024/8/1.1); + int u=(int) (Float.parseFloat(ds)*1024*1024/8/1.1); + ui.setSpeed(d, u); + setVisible(false); + } catch (Exception e2) { + //e2.printStackTrace(); + JOptionPane.showMessageDialog(ui.mainFrame, "输入错误!"); + } + + } + }); + + p6.add(new JLabel(" ")); + + JButton button_cancel=createButton("取消"); + p6.add(button_cancel); + button_cancel.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }); + + pack(); + setLocationRelativeTo(parent); + if(ui.isVisible){ + setVisible(true); + //MLog.println("请在client_config.json中设置带宽"); + } else { + //MLog.println("请在client_config.json中设置带宽"); + //System.exit(0); + } + } + + JButton createButton(String name){ + JButton button=new JButton(name); + button.setMargin(new Insets(0,5,0,5)); + button.setFocusPainted(false); + return button; + } + + + +} diff --git a/src/main/java/net/fs/client/TextComponentPopupMenu.java b/src/main/java/net/fs/client/TextComponentPopupMenu.java new file mode 100755 index 0000000..d0d356c --- /dev/null +++ b/src/main/java/net/fs/client/TextComponentPopupMenu.java @@ -0,0 +1,134 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.client; + +import javax.swing.*; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import javax.swing.text.Position; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +public class TextComponentPopupMenu extends JPopupMenu implements + MouseListener, ActionListener { + + private static final long serialVersionUID = 117096441855319758L; + private static TextComponentPopupMenu sharedInstance = null; + + public static void installToComponent(JComponent c) { + if (c instanceof JTextField && !(c instanceof JPasswordField)) { + c.addMouseListener(TextComponentPopupMenu.getSharedInstance()); + } + } + + public static void uninstallFromComponent(JComponent c) { + if (c instanceof JTextField && !(c instanceof JPasswordField)) { + c.removeMouseListener(getSharedInstance()); + } + } + + JMenuItem cutItem, copyItem, pasteItem, deleteItem, selectAllItem; + + public TextComponentPopupMenu() { + add(cutItem = new JMenuItem("剪切")); + add(copyItem = new JMenuItem("复制")); + add(pasteItem = new JMenuItem("粘贴")); + add(deleteItem = new JMenuItem("删除")); + addSeparator(); + add(selectAllItem = new JMenuItem("全选")); + + cutItem.setMnemonic('T'); + copyItem.setMnemonic('C'); + pasteItem.setMnemonic('P'); + deleteItem.setMnemonic('D'); + selectAllItem.setMnemonic('A'); + + cutItem.addActionListener(this); + copyItem.addActionListener(this); + pasteItem.addActionListener(this); + deleteItem.addActionListener(this); + selectAllItem.addActionListener(this); + } + + static TextComponentPopupMenu getSharedInstance() { + if (sharedInstance == null) { + sharedInstance = new TextComponentPopupMenu(); + } + return sharedInstance; + } + + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger() && e.getSource() instanceof JTextField) { + JTextField textfield = (JTextField) e.getSource(); + if (Boolean.TRUE.equals(textfield + .getClientProperty("DisablePopupMenu"))) { + return; + } + textfield.requestFocusInWindow(); + show(textfield, e.getX(), e.getY()); + } + } + + public void mouseClicked(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void show(Component invoker, int x, int y) { + JTextComponent tc = (JTextComponent) invoker; + String sel = tc.getSelectedText(); + + boolean selected = sel != null && !sel.equals(""); + boolean enableAndEditable = tc.isEnabled() && tc.isEditable(); + + cutItem.setEnabled(selected && enableAndEditable); + copyItem.setEnabled(selected && tc.isEnabled()); + deleteItem.setEnabled(selected && enableAndEditable); + pasteItem.setEnabled(enableAndEditable); + selectAllItem.setEnabled(tc.isEnabled()); + + super.show(invoker, x, y); + } + + public void actionPerformed(ActionEvent e) { + JTextComponent tc = (JTextComponent) getInvoker(); + + String sel = tc.getSelectedText(); + + if (e.getSource() == cutItem) { + tc.cut(); + } else if (e.getSource() == copyItem) { + tc.copy(); + } else if (e.getSource() == pasteItem) { + tc.paste(); + } else if (e.getSource() == selectAllItem) { + tc.selectAll(); + } else if (e.getSource() == deleteItem) { + Document doc = tc.getDocument(); + int start = tc.getSelectionStart(); + int end = tc.getSelectionEnd(); + + try { + Position p0 = doc.createPosition(start); + Position p1 = doc.createPosition(end); + + if ((p0 != null) && (p1 != null) + && (p0.getOffset() != p1.getOffset())) { + doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset()); + } + } catch (BadLocationException be) { + } + } + } +} diff --git a/src/main/java/net/fs/netty/SocksServer.java b/src/main/java/net/fs/netty/SocksServer.java new file mode 100755 index 0000000..607126f --- /dev/null +++ b/src/main/java/net/fs/netty/SocksServer.java @@ -0,0 +1,112 @@ +package net.fs.netty; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.traffic.GlobalTrafficShapingHandler; +import io.netty.handler.traffic.TrafficCounter; + +import java.lang.management.ManagementFactory; +import java.util.concurrent.Executors; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import net.fs.client.ClientUI; +import net.fs.client.FSClient; +import org.apache.commons.cli.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import net.fs.netty.config.Config; +import net.fs.netty.config.ConfigXmlLoader; +import net.fs.netty.config.PacLoader; +import net.fs.netty.mbean.IoAcceptorStat; +import net.fs.netty.proxy.SocksServerInitializer; + +public class SocksServer { + + private static Log logger = LogFactory.getLog(SocksServer.class); + + private static final String CONFIG = "conf/config.xml"; + + private static final String PAC = "conf/pac.xml"; + + private EventLoopGroup bossGroup = null; + private EventLoopGroup workerGroup = null; + private ServerBootstrap bootstrap = null; + private GlobalTrafficShapingHandler trafficHandler; + + private static SocksServer socksServer = new SocksServer(); + + public static SocksServer getInstance() { + return socksServer; + } + + private SocksServer() { + + } + + public void start() { + try { + + FSClient.start(); + + Config config = ConfigXmlLoader.load(CONFIG); + PacLoader.load(PAC); + + bossGroup = new NioEventLoopGroup(1); + workerGroup = new NioEventLoopGroup(); + bootstrap = new ServerBootstrap(); + trafficHandler = new GlobalTrafficShapingHandler( + Executors.newScheduledThreadPool(2), 1000); + + bootstrap + .group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler( + new SocksServerInitializer(config, trafficHandler)); + + logger.info("Start At Port " + config.get_localPort()); + startMBean(); + bootstrap.bind(config.get_localPort()).sync().channel() + .closeFuture().sync(); + } catch (Exception e) { + logger.error("start error", e); + } finally { + stop(); + } + } + + public void stop() { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + logger.info("Stop Server!"); + } + + /** + * java MBean 进行流量统计 + */ + private void startMBean() { + MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + IoAcceptorStat mbean = new IoAcceptorStat(); + + try { + ObjectName acceptorName = new ObjectName(mbean.getClass() + .getPackage().getName() + + ":type=IoAcceptorStat"); + mBeanServer.registerMBean(mbean, acceptorName); + } catch (Exception e) { + logger.error("java MBean error", e); + } + } + + public TrafficCounter getTrafficCounter() { + return trafficHandler.trafficCounter(); + } + +} diff --git a/src/main/java/net/fs/netty/Start.java b/src/main/java/net/fs/netty/Start.java new file mode 100755 index 0000000..259d1c0 --- /dev/null +++ b/src/main/java/net/fs/netty/Start.java @@ -0,0 +1,22 @@ +package net.fs.netty; + +import java.net.ServerSocket; +import java.net.Socket; + +/** + * socksserver启动类 + * + * @author zhangjianxin + * + */ +public class Start { + + public static void main(String[] args) { + SocksServer.getInstance().start(); + try { + }catch (Exception e){ + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/net/fs/netty/config/Config.java b/src/main/java/net/fs/netty/config/Config.java new file mode 100755 index 0000000..324453b --- /dev/null +++ b/src/main/java/net/fs/netty/config/Config.java @@ -0,0 +1,80 @@ +package net.fs.netty.config; + +/** + * 配置 + * + * @author zhangjianxin + * + */ +public class Config { + + private String _ipAddr; + private int _port; + private String _localIpAddr; + private int _localPort; + private String _method; + private String _password; + + public Config() { + + } + + public Config(String ipAddr, int port, String localIpAddr, int localPort, + String method, String password) { + _ipAddr = ipAddr; + _port = port; + _localIpAddr = localIpAddr; + _localPort = localPort; + _method = method; + _password = password; + } + + public String get_ipAddr() { + return _ipAddr; + } + + public void set_ipAddr(String _ipAddr) { + this._ipAddr = _ipAddr; + } + + public int get_port() { + return _port; + } + + public void set_port(int _port) { + this._port = _port; + } + + public String get_localIpAddr() { + return _localIpAddr; + } + + public void set_localIpAddr(String _localIpAddr) { + this._localIpAddr = _localIpAddr; + } + + public int get_localPort() { + return _localPort; + } + + public void set_localPort(int _localPort) { + this._localPort = _localPort; + } + + public String get_method() { + return _method; + } + + public void set_method(String _method) { + this._method = _method; + } + + public String get_password() { + return _password; + } + + public void set_password(String _password) { + this._password = _password; + } + +} diff --git a/src/main/java/net/fs/netty/config/ConfigXmlLoader.java b/src/main/java/net/fs/netty/config/ConfigXmlLoader.java new file mode 100755 index 0000000..9918aab --- /dev/null +++ b/src/main/java/net/fs/netty/config/ConfigXmlLoader.java @@ -0,0 +1,72 @@ +package net.fs.netty.config; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * 加载Config配置xml + * + * @author zhangjianxin + * + */ +public class ConfigXmlLoader { + + private static Logger log = Logger.getLogger(ConfigXmlLoader.class); + + public static Config load(String file) throws Exception { + InputStream in = null; + try { + DocumentBuilder builder = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + in = new FileInputStream(file); + Document doc = builder.parse(in); + NodeList list = doc.getElementsByTagName("config"); + + Config config = new Config(); + if (list.getLength() > 0) { + Node node = list.item(0); + NodeList childs = node.getChildNodes(); + + for (int j = 0; j < childs.getLength(); j++) { + if ("ip_addr".equals(childs.item(j).getNodeName())) { + config.set_ipAddr(childs.item(j).getTextContent()); + } else if ("port".equals(childs.item(j).getNodeName())) { + config.set_port(Integer.parseInt(childs.item(j) + .getTextContent())); + } else if ("local_ip_addr".equals(childs.item(j) + .getNodeName())) { + config.set_localIpAddr(childs.item(j).getTextContent()); + } else if ("local_port" + .equals(childs.item(j).getNodeName())) { + config.set_localPort(Integer.parseInt(childs.item(j) + .getTextContent())); + } else if ("method".equals(childs.item(j).getNodeName())) { + config.set_method(childs.item(j).getTextContent()); + } else if ("password".equals(childs.item(j).getNodeName())) { + config.set_password(childs.item(j).getTextContent()); + } + } + } + log.info("load config !"); + return config; + } catch (Exception e) { + throw e; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + } + } + } + } +} diff --git a/src/main/java/net/fs/netty/config/PacLoader.java b/src/main/java/net/fs/netty/config/PacLoader.java new file mode 100755 index 0000000..0c564ce --- /dev/null +++ b/src/main/java/net/fs/netty/config/PacLoader.java @@ -0,0 +1,114 @@ +package net.fs.netty.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +/** + * 加载pac配置xml + * + * @author zhangjianxin + * + */ +public class PacLoader { + + private static Logger log = Logger.getLogger(PacLoader.class); + + private static List domainList = new ArrayList(); + private static List tempList = new ArrayList(); + + /** 重加载的间隔时间 **/ + private static int reloadTime = 5; + + private static long lastModify; + + public static void load(final String filePath) throws Exception { + File file = new File(filePath); + if (!file.exists()) { + throw new RuntimeException("file = " + filePath + " is not exist!"); + } + if (file.lastModified() == lastModify) { + return; + } + lastModify = file.lastModified(); + + loadFile(filePath); + + Executors.newScheduledThreadPool(1).scheduleWithFixedDelay( + new Runnable() { + + @Override + public void run() { + try { + load(filePath); + } catch (Exception e) { + log.error(e); + } + } + }, reloadTime, reloadTime, TimeUnit.SECONDS); + } + + private synchronized static void loadFile(String file) throws Exception { + tempList.clear(); + InputStream in = null; + try { + DocumentBuilder builder = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + in = new FileInputStream(file); + Document doc = builder.parse(in); + NodeList list = doc.getElementsByTagName("domain"); + + if (list.getLength() > 0) { + for (int j = 0; j < list.getLength(); j++) { + tempList.add(list.item(j).getTextContent()); + } + } + setDomainList(tempList); + log.info("Load PAC Success!"); + } catch (Exception e) { + throw e; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + } + } + } + } + + private synchronized static void setDomainList(List tempList) { + domainList.clear(); + domainList.addAll(tempList); + } + + /** + * 指定的host是否需要代理 + * + * @param host + * @return + */ + public synchronized static boolean isProxy(String host) { + for (String domain : domainList) { + if (host.contains(domain)) { + return true; + } + } + //return false; + //默认配置PAC + //测试阶段采用全部经过NETTY的请求都要经过代理 SS-Server:443 + return true; + } +} diff --git a/src/main/java/net/fs/netty/encryption/CryptBase.java b/src/main/java/net/fs/netty/encryption/CryptBase.java new file mode 100755 index 0000000..10ded06 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/CryptBase.java @@ -0,0 +1,143 @@ +package net.fs.netty.encryption; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; + +import javax.crypto.SecretKey; + +import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; + +public abstract class CryptBase implements ICrypt { + + protected final String _name; + protected final SecretKey _key; + protected final ShadowSocksKey _ssKey; + protected final int _ivLength; + protected final int _keyLength; + protected boolean _encryptIVSet; + protected boolean _decryptIVSet; + protected byte[] _encryptIV; + protected byte[] _decryptIV; + protected final Lock encLock = new ReentrantLock(); + protected final Lock decLock = new ReentrantLock(); + protected StreamBlockCipher encCipher; + protected StreamBlockCipher decCipher; + private Logger logger = Logger.getLogger(CryptBase.class.getName()); + + public CryptBase(String name, String password) { + _name = name.toLowerCase(); + _ivLength = getIVLength(); + _keyLength = getKeyLength(); + _ssKey = new ShadowSocksKey(password, _keyLength); + _key = getKey(); + } + + protected void setIV(byte[] iv, boolean isEncrypt) { + if (_ivLength == 0) { + return; + } + + if (isEncrypt) { + _encryptIV = new byte[_ivLength]; + System.arraycopy(iv, 0, _encryptIV, 0, _ivLength); + try { + encCipher = getCipher(isEncrypt); + ParametersWithIV parameterIV = new ParametersWithIV( + new KeyParameter(_key.getEncoded()), _encryptIV); + encCipher.init(isEncrypt, parameterIV); + } catch (InvalidAlgorithmParameterException e) { + logger.info(e.toString()); + } + } else { + _decryptIV = new byte[_ivLength]; + System.arraycopy(iv, 0, _decryptIV, 0, _ivLength); + try { + decCipher = getCipher(isEncrypt); + ParametersWithIV parameterIV = new ParametersWithIV( + new KeyParameter(_key.getEncoded()), _decryptIV); + decCipher.init(isEncrypt, parameterIV); + } catch (InvalidAlgorithmParameterException e) { + logger.info(e.toString()); + } + } + } + + @Override + public void encrypt(byte[] data, ByteArrayOutputStream stream) { + synchronized (encLock) { + stream.reset(); + if (!_encryptIVSet) { + _encryptIVSet = true; + byte[] iv = randomBytes(_ivLength); + setIV(iv, true); + try { + stream.write(iv); + } catch (IOException e) { + logger.info(e.toString()); + } + + } + + _encrypt(data, stream); + } + } + + @Override + public void encrypt(byte[] data, int length, ByteArrayOutputStream stream) { + byte[] d = new byte[length]; + System.arraycopy(data, 0, d, 0, length); + encrypt(d, stream); + } + + @Override + public void decrypt(byte[] data, ByteArrayOutputStream stream) { + byte[] temp; + synchronized (decLock) { + stream.reset(); + if (!_decryptIVSet) { + _decryptIVSet = true; + setIV(data, false); + temp = new byte[data.length - _ivLength]; + System.arraycopy(data, _ivLength, temp, 0, data.length + - _ivLength); + } else { + temp = data; + } + + _decrypt(temp, stream); + } + } + + @Override + public void decrypt(byte[] data, int length, ByteArrayOutputStream stream) { + byte[] d = new byte[length]; + System.arraycopy(data, 0, d, 0, length); + decrypt(d, stream); + } + + private byte[] randomBytes(int size) { + byte[] bytes = new byte[size]; + new SecureRandom().nextBytes(bytes); + return bytes; + } + + protected abstract StreamBlockCipher getCipher(boolean isEncrypted) + throws InvalidAlgorithmParameterException; + + protected abstract SecretKey getKey(); + + protected abstract void _encrypt(byte[] data, ByteArrayOutputStream stream); + + protected abstract void _decrypt(byte[] data, ByteArrayOutputStream stream); + + protected abstract int getIVLength(); + + protected abstract int getKeyLength(); +} diff --git a/src/main/java/net/fs/netty/encryption/CryptFactory.java b/src/main/java/net/fs/netty/encryption/CryptFactory.java new file mode 100755 index 0000000..3060536 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/CryptFactory.java @@ -0,0 +1,44 @@ +package net.fs.netty.encryption; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import net.fs.netty.encryption.impl.AesCrypt; +import net.fs.netty.encryption.impl.BlowFishCrypt; +import net.fs.netty.encryption.impl.CamelliaCrypt; +import net.fs.netty.encryption.impl.SeedCrypt; + +public class CryptFactory { + + private static Log logger = LogFactory.getLog(CryptFactory.class); + + private static Map crypts = new HashMap(); + + static { + crypts.putAll(AesCrypt.getCiphers()); + crypts.putAll(CamelliaCrypt.getCiphers()); + crypts.putAll(BlowFishCrypt.getCiphers()); + crypts.putAll(SeedCrypt.getCiphers()); + } + + public static ICrypt get(String name, String password) { + String className = crypts.get(name); + if (className == null) { + return null; + } + + try { + Class clazz = Class.forName(className); + Constructor constructor = clazz.getConstructor(String.class, + String.class); + return (ICrypt) constructor.newInstance(name, password); + } catch (Exception e) { + logger.error("get crypt error", e); + } + + return null; + } +} diff --git a/src/main/java/net/fs/netty/encryption/ICrypt.java b/src/main/java/net/fs/netty/encryption/ICrypt.java new file mode 100755 index 0000000..885c549 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/ICrypt.java @@ -0,0 +1,21 @@ +package net.fs.netty.encryption; + +import java.io.ByteArrayOutputStream; + +/** + * crypt 加密 + * + * @author zhangjianxin + * + */ +public interface ICrypt { + + void encrypt(byte[] data, ByteArrayOutputStream stream); + + void encrypt(byte[] data, int length, ByteArrayOutputStream stream); + + void decrypt(byte[] data, ByteArrayOutputStream stream); + + void decrypt(byte[] data, int length, ByteArrayOutputStream stream); + +} diff --git a/src/main/java/net/fs/netty/encryption/ShadowSocksKey.java b/src/main/java/net/fs/netty/encryption/ShadowSocksKey.java new file mode 100755 index 0000000..8fd8fa2 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/ShadowSocksKey.java @@ -0,0 +1,86 @@ +package net.fs.netty.encryption; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; + +import javax.crypto.SecretKey; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Shadowsocks key generator + */ +public class ShadowSocksKey implements SecretKey { + + private static final long serialVersionUID = 1L; + private static Log logger = LogFactory.getLog(ShadowSocksKey.class); + private final static int KEY_LENGTH = 32; + private byte[] _key; + private int _length; + + public ShadowSocksKey(String password) { + _length = KEY_LENGTH; + _key = init(password); + } + + public ShadowSocksKey(String password, int length) { + _length = length; + _key = init(password); + } + + private byte[] init(String password) { + MessageDigest md = null; + byte[] keys = new byte[KEY_LENGTH]; + byte[] temp = null; + byte[] hash = null; + byte[] passwordBytes = null; + int i = 0; + + try { + md = MessageDigest.getInstance("MD5"); + passwordBytes = password.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + logger.error("ShadowSocksKey: Unsupported string encoding", e); + } catch (Exception e) { + logger.error(e); + return null; + } + + while (i < keys.length) { + if (i == 0) { + hash = md.digest(passwordBytes); + temp = new byte[passwordBytes.length + hash.length]; + } else { + System.arraycopy(hash, 0, temp, 0, hash.length); + System.arraycopy(passwordBytes, 0, temp, hash.length, + passwordBytes.length); + hash = md.digest(temp); + } + System.arraycopy(hash, 0, keys, i, hash.length); + i += hash.length; + } + + if (_length != KEY_LENGTH) { + byte[] keysl = new byte[_length]; + System.arraycopy(keys, 0, keysl, 0, _length); + return keysl; + } + return keys; + } + + @Override + public String getAlgorithm() { + return "shadowsocks"; + } + + @Override + public String getFormat() { + return "RAW"; + } + + @Override + public byte[] getEncoded() { + return _key; + } +} diff --git a/src/main/java/net/fs/netty/encryption/impl/AesCrypt.java b/src/main/java/net/fs/netty/encryption/impl/AesCrypt.java new file mode 100755 index 0000000..5bdb696 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/impl/AesCrypt.java @@ -0,0 +1,118 @@ +package net.fs.netty.encryption.impl; + +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.modes.CFBBlockCipher; +import org.bouncycastle.crypto.modes.OFBBlockCipher; +import net.fs.netty.encryption.CryptBase; + +/** + * AES 实现类 + * + * @author zhangjianxin + * + */ +public class AesCrypt extends CryptBase { + + public final static String CIPHER_AES_128_CFB = "aes-128-cfb"; + public final static String CIPHER_AES_192_CFB = "aes-192-cfb"; + public final static String CIPHER_AES_256_CFB = "aes-256-cfb"; + public final static String CIPHER_AES_128_OFB = "aes-128-ofb"; + public final static String CIPHER_AES_192_OFB = "aes-192-ofb"; + public final static String CIPHER_AES_256_OFB = "aes-256-ofb"; + + public static Map getCiphers() { + Map ciphers = new HashMap<>(); + ciphers.put(CIPHER_AES_128_CFB, AesCrypt.class.getName()); + ciphers.put(CIPHER_AES_192_CFB, AesCrypt.class.getName()); + ciphers.put(CIPHER_AES_256_CFB, AesCrypt.class.getName()); + ciphers.put(CIPHER_AES_128_OFB, AesCrypt.class.getName()); + ciphers.put(CIPHER_AES_192_OFB, AesCrypt.class.getName()); + ciphers.put(CIPHER_AES_256_OFB, AesCrypt.class.getName()); + + return ciphers; + } + + public AesCrypt(String name, String password) { + super(name, password); + } + + @Override + public int getKeyLength() { + if (_name.equals(CIPHER_AES_128_CFB) + || _name.equals(CIPHER_AES_128_OFB)) { + return 16; + } else if (_name.equals(CIPHER_AES_192_CFB) + || _name.equals(CIPHER_AES_192_OFB)) { + return 24; + } else if (_name.equals(CIPHER_AES_256_CFB) + || _name.equals(CIPHER_AES_256_OFB)) { + return 32; + } + + return 0; + } + + @Override + protected StreamBlockCipher getCipher(boolean isEncrypted) + throws InvalidAlgorithmParameterException { + AESFastEngine engine = new AESFastEngine(); + StreamBlockCipher cipher; + + if (_name.equals(CIPHER_AES_128_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } else if (_name.equals(CIPHER_AES_192_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } else if (_name.equals(CIPHER_AES_256_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } else if (_name.equals(CIPHER_AES_128_OFB)) { + cipher = new OFBBlockCipher(engine, getIVLength() * 8); + } else if (_name.equals(CIPHER_AES_192_OFB)) { + cipher = new OFBBlockCipher(engine, getIVLength() * 8); + } else if (_name.equals(CIPHER_AES_256_OFB)) { + cipher = new OFBBlockCipher(engine, getIVLength() * 8); + } else { + throw new InvalidAlgorithmParameterException(_name); + } + + return cipher; + } + + @Override + public int getIVLength() { + return 16; + } + + @Override + protected SecretKey getKey() { + return new SecretKeySpec(_ssKey.getEncoded(), "AES"); + } + + @Override + protected void _encrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = encCipher.processBytes(data, 0, data.length, buffer, + 0); + stream.write(buffer, 0, noBytesProcessed); + } + + @Override + protected void _decrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = decCipher.processBytes(data, 0, data.length, buffer, + 0); + stream.write(buffer, 0, noBytesProcessed); + } +} diff --git a/src/main/java/net/fs/netty/encryption/impl/BlowFishCrypt.java b/src/main/java/net/fs/netty/encryption/impl/BlowFishCrypt.java new file mode 100755 index 0000000..a66cc78 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/impl/BlowFishCrypt.java @@ -0,0 +1,80 @@ +package net.fs.netty.encryption.impl; + +import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.crypto.engines.BlowfishEngine; +import org.bouncycastle.crypto.modes.CFBBlockCipher; +import net.fs.netty.encryption.CryptBase; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.util.HashMap; +import java.util.Map; + +/** + * Blow fish cipher implementation + */ +public class BlowFishCrypt extends CryptBase { + + public final static String CIPHER_BLOWFISH_CFB = "bf-cfb"; + + public static Map getCiphers() { + Map ciphers = new HashMap<>(); + ciphers.put(CIPHER_BLOWFISH_CFB, BlowFishCrypt.class.getName()); + + return ciphers; + } + + public BlowFishCrypt(String name, String password) { + super(name, password); + } + + @Override + public int getKeyLength() { + return 16; + } + + @Override + protected StreamBlockCipher getCipher(boolean isEncrypted) throws InvalidAlgorithmParameterException { + BlowfishEngine engine = new BlowfishEngine(); + StreamBlockCipher cipher; + + if (_name.equals(CIPHER_BLOWFISH_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } + else { + throw new InvalidAlgorithmParameterException(_name); + } + + return cipher; + } + + @Override + public int getIVLength() { + return 8; + } + + @Override + protected SecretKey getKey() { + return new SecretKeySpec(_ssKey.getEncoded(), "AES"); + } + + @Override + protected void _encrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = encCipher.processBytes(data, 0, data.length, buffer, 0); + stream.write(buffer, 0, noBytesProcessed); + } + + @Override + protected void _decrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = decCipher.processBytes(data, 0, data.length, buffer, 0); + stream.write(buffer, 0, noBytesProcessed); + } +} diff --git a/src/main/java/net/fs/netty/encryption/impl/CamelliaCrypt.java b/src/main/java/net/fs/netty/encryption/impl/CamelliaCrypt.java new file mode 100755 index 0000000..5202da7 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/impl/CamelliaCrypt.java @@ -0,0 +1,100 @@ +package net.fs.netty.encryption.impl; + +import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.crypto.engines.CamelliaEngine; +import org.bouncycastle.crypto.modes.CFBBlockCipher; +import net.fs.netty.encryption.CryptBase; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.util.HashMap; +import java.util.Map; + +/** + * Camellia cipher implementation + */ +public class CamelliaCrypt extends CryptBase { + + public final static String CIPHER_CAMELLIA_128_CFB = "camellia-128-cfb"; + public final static String CIPHER_CAMELLIA_192_CFB = "camellia-192-cfb"; + public final static String CIPHER_CAMELLIA_256_CFB = "camellia-256-cfb"; + + public static Map getCiphers() { + Map ciphers = new HashMap<>(); + ciphers.put(CIPHER_CAMELLIA_128_CFB, CamelliaCrypt.class.getName()); + ciphers.put(CIPHER_CAMELLIA_192_CFB, CamelliaCrypt.class.getName()); + ciphers.put(CIPHER_CAMELLIA_256_CFB, CamelliaCrypt.class.getName()); + + return ciphers; + } + + public CamelliaCrypt(String name, String password) { + super(name, password); + } + + @Override + public int getKeyLength() { + if(_name.equals(CIPHER_CAMELLIA_128_CFB)) { + return 16; + } + else if (_name.equals(CIPHER_CAMELLIA_192_CFB)) { + return 24; + } + else if (_name.equals(CIPHER_CAMELLIA_256_CFB)) { + return 32; + } + + return 0; + } + + @Override + protected StreamBlockCipher getCipher(boolean isEncrypted) throws InvalidAlgorithmParameterException { + CamelliaEngine engine = new CamelliaEngine(); + StreamBlockCipher cipher; + + if (_name.equals(CIPHER_CAMELLIA_128_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } + else if (_name.equals(CIPHER_CAMELLIA_192_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } + else if (_name.equals(CIPHER_CAMELLIA_256_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } + else { + throw new InvalidAlgorithmParameterException(_name); + } + + return cipher; + } + + @Override + public int getIVLength() { + return 16; + } + + @Override + protected SecretKey getKey() { + return new SecretKeySpec(_ssKey.getEncoded(), "AES"); + } + + @Override + protected void _encrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = encCipher.processBytes(data, 0, data.length, buffer, 0); + stream.write(buffer, 0, noBytesProcessed); + } + + @Override + protected void _decrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = decCipher.processBytes(data, 0, data.length, buffer, 0); + stream.write(buffer, 0, noBytesProcessed); + } +} diff --git a/src/main/java/net/fs/netty/encryption/impl/SeedCrypt.java b/src/main/java/net/fs/netty/encryption/impl/SeedCrypt.java new file mode 100755 index 0000000..f646451 --- /dev/null +++ b/src/main/java/net/fs/netty/encryption/impl/SeedCrypt.java @@ -0,0 +1,80 @@ +package net.fs.netty.encryption.impl; + +import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.crypto.engines.SEEDEngine; +import org.bouncycastle.crypto.modes.CFBBlockCipher; +import net.fs.netty.encryption.CryptBase; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.util.HashMap; +import java.util.Map; + +/** + * Seed cipher implementation + */ +public class SeedCrypt extends CryptBase { + + public final static String CIPHER_SEED_CFB = "seed-cfb"; + + public static Map getCiphers() { + Map ciphers = new HashMap<>(); + ciphers.put(CIPHER_SEED_CFB, SeedCrypt.class.getName()); + + return ciphers; + } + + public SeedCrypt(String name, String password) { + super(name, password); + } + + @Override + public int getKeyLength() { + return 16; + } + + @Override + protected StreamBlockCipher getCipher(boolean isEncrypted) throws InvalidAlgorithmParameterException { + SEEDEngine engine = new SEEDEngine(); + StreamBlockCipher cipher; + + if (_name.equals(CIPHER_SEED_CFB)) { + cipher = new CFBBlockCipher(engine, getIVLength() * 8); + } + else { + throw new InvalidAlgorithmParameterException(_name); + } + + return cipher; + } + + @Override + public int getIVLength() { + return 16; + } + + @Override + protected SecretKey getKey() { + return new SecretKeySpec(_ssKey.getEncoded(), "AES"); + } + + @Override + protected void _encrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = encCipher.processBytes(data, 0, data.length, buffer, 0); + stream.write(buffer, 0, noBytesProcessed); + } + + @Override + protected void _decrypt(byte[] data, ByteArrayOutputStream stream) { + int noBytesProcessed; + byte[] buffer = new byte[data.length]; + + noBytesProcessed = decCipher.processBytes(data, 0, data.length, buffer, 0); + stream.write(buffer, 0, noBytesProcessed); + } +} diff --git a/src/main/java/net/fs/netty/mbean/IoAcceptorStat.java b/src/main/java/net/fs/netty/mbean/IoAcceptorStat.java new file mode 100755 index 0000000..c753b66 --- /dev/null +++ b/src/main/java/net/fs/netty/mbean/IoAcceptorStat.java @@ -0,0 +1,19 @@ +package net.fs.netty.mbean; + +import net.fs.netty.SocksServer; + +public class IoAcceptorStat implements IoAcceptorStatMBean { + + @Override + public long getWrittenBytesThroughput() { + return SocksServer.getInstance().getTrafficCounter() + .lastWriteThroughput(); + } + + @Override + public long getReadBytesThroughput() { + return SocksServer.getInstance().getTrafficCounter() + .lastReadThroughput(); + } + +} diff --git a/src/main/java/net/fs/netty/mbean/IoAcceptorStatMBean.java b/src/main/java/net/fs/netty/mbean/IoAcceptorStatMBean.java new file mode 100755 index 0000000..4907337 --- /dev/null +++ b/src/main/java/net/fs/netty/mbean/IoAcceptorStatMBean.java @@ -0,0 +1,18 @@ +package net.fs.netty.mbean; + +public interface IoAcceptorStatMBean { + + /** + * netty写流量 bytes/s 对浏览器来说其实就是下载速度 + * + * @return + */ + public long getWrittenBytesThroughput(); + + /** + * netty 读流量 bytes/s 对浏览器来说其实就是上传速度 + * + * @return + */ + public long getReadBytesThroughput(); +} diff --git a/src/main/java/net/fs/netty/proxy/DirectClientHandler.java b/src/main/java/net/fs/netty/proxy/DirectClientHandler.java new file mode 100755 index 0000000..a38daf4 --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/DirectClientHandler.java @@ -0,0 +1,26 @@ +package net.fs.netty.proxy; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.concurrent.Promise; + +public final class DirectClientHandler extends ChannelInboundHandlerAdapter { + + private final Promise promise; + + public DirectClientHandler(Promise promise) { + this.promise = promise; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.pipeline().remove(this); + promise.setSuccess(ctx.channel()); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) { + promise.setFailure(throwable); + } +} diff --git a/src/main/java/net/fs/netty/proxy/InRelayHandler.java b/src/main/java/net/fs/netty/proxy/InRelayHandler.java new file mode 100755 index 0000000..97740ac --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/InRelayHandler.java @@ -0,0 +1,69 @@ +package net.fs.netty.proxy; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.ReferenceCountUtil; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * 接受remoteserver的数据,发送给客户端 + * + * @author zhangjianxin + * + */ +public final class InRelayHandler extends ChannelInboundHandlerAdapter { + + private static Log logger = LogFactory.getLog(InRelayHandler.class); + + private final Channel relayChannel; + private SocksServerConnectHandler connectHandler; + + public InRelayHandler(Channel relayChannel, + SocksServerConnectHandler connectHandler) { + this.relayChannel = relayChannel; + this.connectHandler = connectHandler; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + try { + if (relayChannel.isActive()) { + logger.debug("get remote message" + relayChannel); + ByteBuf bytebuff = (ByteBuf) msg; + if (!bytebuff.hasArray()) { + int len = bytebuff.readableBytes(); + byte[] arr = new byte[len]; + bytebuff.getBytes(0, arr); + connectHandler.sendLocal(arr, arr.length, relayChannel); + } + } + } catch (Exception e) { + logger.error("receive remoteServer data error", e); + } finally { + ReferenceCountUtil.release(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + if (relayChannel.isActive()) { + SocksServerUtils.closeOnFlush(relayChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} diff --git a/src/main/java/net/fs/netty/proxy/OutRelayHandler.java b/src/main/java/net/fs/netty/proxy/OutRelayHandler.java new file mode 100755 index 0000000..f747189 --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/OutRelayHandler.java @@ -0,0 +1,69 @@ +package net.fs.netty.proxy; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.ReferenceCountUtil; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * localserver接受到数据发送数据给remoteserver + * + * @author zhangjianxin + * + */ +public final class OutRelayHandler extends ChannelInboundHandlerAdapter { + + private static Log logger = LogFactory.getLog(OutRelayHandler.class); + + private final Channel relayChannel; + private SocksServerConnectHandler connectHandler; + + public OutRelayHandler(Channel relayChannel, + SocksServerConnectHandler connectHandler) { + this.relayChannel = relayChannel; + this.connectHandler = connectHandler; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + try { + if (relayChannel.isActive()) { + ByteBuf bytebuff = (ByteBuf) msg; + if (!bytebuff.hasArray()) { + int len = bytebuff.readableBytes(); + byte[] arr = new byte[len]; + bytebuff.getBytes(0, arr); + connectHandler.sendRemote(arr, arr.length, relayChannel); + } + } + } catch (Exception e) { + logger.error("send data to remoteServer error",e); + } finally { + ReferenceCountUtil.release(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + if (relayChannel.isActive()) { + SocksServerUtils.closeOnFlush(relayChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } + +} diff --git a/src/main/java/net/fs/netty/proxy/SocksServerConnectHandler.java b/src/main/java/net/fs/netty/proxy/SocksServerConnectHandler.java new file mode 100755 index 0000000..10b1fbf --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/SocksServerConnectHandler.java @@ -0,0 +1,229 @@ +package net.fs.netty.proxy; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOption; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.socks.SocksCmdRequest; +import io.netty.handler.codec.socks.SocksCmdResponse; +import io.netty.handler.codec.socks.SocksCmdStatus; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.concurrent.Promise; + +import java.io.ByteArrayOutputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import net.fs.netty.config.Config; +import net.fs.netty.config.PacLoader; +import net.fs.netty.encryption.CryptFactory; +import net.fs.netty.encryption.ICrypt; + +@ChannelHandler.Sharable +public final class SocksServerConnectHandler extends + SimpleChannelInboundHandler { + + private static Log logger = LogFactory + .getLog(SocksServerConnectHandler.class); + + public static final int BUFFER_SIZE = 16384; + + private final Bootstrap b = new Bootstrap(); + private ICrypt _crypt; + private ByteArrayOutputStream _remoteOutStream; + private ByteArrayOutputStream _localOutStream; + private Config config; + private boolean isProxy = true; + + public SocksServerConnectHandler(Config config) { + this.config = config; + this._crypt = CryptFactory.get(config.get_method(), config.get_password()); + this._remoteOutStream = new ByteArrayOutputStream(BUFFER_SIZE); + this._localOutStream = new ByteArrayOutputStream(BUFFER_SIZE); + } + + @Override + public void channelRead0(final ChannelHandlerContext ctx, + final SocksCmdRequest request) throws Exception { + Promise promise = ctx.executor().newPromise(); + promise.addListener(new GenericFutureListener>() { + @Override + public void operationComplete(final Future future) + throws Exception { + final Channel outboundChannel = future.getNow(); + if (future.isSuccess()) { + final InRelayHandler inRelay = new InRelayHandler(ctx + .channel(), SocksServerConnectHandler.this); + final OutRelayHandler outRelay = new OutRelayHandler( + outboundChannel, SocksServerConnectHandler.this); + + ctx.channel().writeAndFlush(getSuccessResponse(request)) + .addListener(new ChannelFutureListener() { + @Override + public void operationComplete( + ChannelFuture channelFuture) { + try { + if(isProxy){ + sendConnectRemoteMessage(request, outboundChannel); + } + + ctx.pipeline().remove(SocksServerConnectHandler.this); + outboundChannel.pipeline().addLast(inRelay); + ctx.pipeline().addLast(outRelay); + } catch (Exception e) { + logger.error(e); + } + } + }); + } else { + ctx.channel().writeAndFlush( + new SocksCmdResponse(SocksCmdStatus.FAILURE, + request.addressType())); + SocksServerUtils.closeOnFlush(ctx.channel()); + } + } + }); + + final Channel inboundChannel = ctx.channel(); + b.group(inboundChannel.eventLoop()).channel(NioSocketChannel.class) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) + .option(ChannelOption.SO_KEEPALIVE, true) + .handler(new DirectClientHandler(promise)); + + setProxy(request.host()); + + b.connect(getIpAddr(request), getPort(request)).addListener( + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) + throws Exception { + if (!future.isSuccess()) { + ctx.channel().writeAndFlush(getFailureResponse(request)); + SocksServerUtils.closeOnFlush(ctx.channel()); + } + } + }); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) + throws Exception { + SocksServerUtils.closeOnFlush(ctx.channel()); + } + + public void setProxy(String host) { + isProxy = PacLoader.isProxy(host); + logger.info("HOST = " + host + ",isProxy = " + isProxy); + } + + /** + * 获取远程ip地址 + * @param request + * @return + */ + private String getIpAddr(SocksCmdRequest request) { + if(isProxy) { + return config.get_ipAddr(); + } else { + return request.host(); + } + } + + /** + * 获取远程端口 + * @param request + * @return + */ + private int getPort(SocksCmdRequest request) { + if(isProxy) { + return config.get_port(); + } else { + return request.port(); + } + } + + private SocksCmdResponse getSuccessResponse(SocksCmdRequest request) { + return new SocksCmdResponse(SocksCmdStatus.SUCCESS, + request.addressType()); + } + + private SocksCmdResponse getFailureResponse(SocksCmdRequest request) { + return new SocksCmdResponse(SocksCmdStatus.FAILURE, + request.addressType()); + } + + /** + * localserver和remoteserver进行connect发送的数据 + * + * @param request + * @param outboundChannel + */ + private void sendConnectRemoteMessage(SocksCmdRequest request, + Channel outboundChannel) { + ByteBuf buff = Unpooled.buffer(); + request.encodeAsByteBuf(buff); + if (buff.hasArray()) { + int len = buff.readableBytes(); + byte[] arr = new byte[len]; + buff.getBytes(0, arr); + byte[] data = remoteByte(arr); + sendRemote(data, data.length, outboundChannel); + } + } + + /** + * localserver和remoteserver进行connect发送的数据 + * + * +-----+-----+-------+------+----------+----------+ + * | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | + * +-----+-----+-------+------+----------+----------+ + * | 1 | 1 | X'00' | 1 | Variable | 2 | + * +-----+-----+-------+------+----------+----------+ + * + * 需要跳过前面3个字节 + * + * @param data + * @return + */ + private byte[] remoteByte(byte[] data) { + int dataLength = data.length; + dataLength -= 3; + byte[] temp = new byte[dataLength]; + System.arraycopy(data, 3, temp, 0, dataLength); + return temp; + } + + /** + * 给remoteserver发送数据--需要进行加密处理 + * + * @param data + * @param length + * @param channel + */ + public void sendRemote(byte[] data, int length, Channel channel) { + if(isProxy) { + _crypt.encrypt(data, length, _remoteOutStream); + data = _remoteOutStream.toByteArray(); + } + channel.writeAndFlush(Unpooled.wrappedBuffer(data)); + logger.debug("sendRemote message:isProxy = " + isProxy +",length = " + length+",channel = " + channel); + } + + public void sendLocal(byte[] data, int length, Channel outboundChannel) { + if(isProxy) { + _crypt.decrypt(data, length, _localOutStream); + data = _localOutStream.toByteArray(); + } + outboundChannel.writeAndFlush(Unpooled.wrappedBuffer(data)); + logger.debug("sendLocal message:isProxy = " + isProxy +",length = " + length + ",channel = " + outboundChannel); + } + +} diff --git a/src/main/java/net/fs/netty/proxy/SocksServerHandler.java b/src/main/java/net/fs/netty/proxy/SocksServerHandler.java new file mode 100755 index 0000000..4a429d5 --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/SocksServerHandler.java @@ -0,0 +1,72 @@ +package net.fs.netty.proxy; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import net.fs.netty.config.Config; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.socks.SocksAuthResponse; +import io.netty.handler.codec.socks.SocksAuthScheme; +import io.netty.handler.codec.socks.SocksAuthStatus; +import io.netty.handler.codec.socks.SocksCmdRequest; +import io.netty.handler.codec.socks.SocksCmdRequestDecoder; +import io.netty.handler.codec.socks.SocksCmdType; +import io.netty.handler.codec.socks.SocksInitResponse; +import io.netty.handler.codec.socks.SocksRequest; + +@ChannelHandler.Sharable +public final class SocksServerHandler extends + SimpleChannelInboundHandler { + + private static Log logger = LogFactory.getLog(SocksServerHandler.class); + + private Config config; + + public SocksServerHandler(Config config) { + this.config = config; + } + + @Override + public void channelRead0(ChannelHandlerContext ctx, + SocksRequest socksRequest) throws Exception { + switch (socksRequest.requestType()) { + case INIT: { + logger.info("localserver init"); + ctx.pipeline().addFirst(new SocksCmdRequestDecoder()); + ctx.write(new SocksInitResponse(SocksAuthScheme.NO_AUTH)); + break; + } + case AUTH: + ctx.pipeline().addFirst(new SocksCmdRequestDecoder()); + ctx.write(new SocksAuthResponse(SocksAuthStatus.SUCCESS)); + break; + case CMD: + SocksCmdRequest req = (SocksCmdRequest) socksRequest; + if (req.cmdType() == SocksCmdType.CONNECT) { + logger.info("localserver connect"); + ctx.pipeline().addLast(new SocksServerConnectHandler(config)); + ctx.pipeline().remove(this); + ctx.fireChannelRead(socksRequest); + } else { + ctx.close(); + } + break; + case UNKNOWN: + ctx.close(); + break; + } + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) { + throwable.printStackTrace(); + SocksServerUtils.closeOnFlush(ctx.channel()); + } +} diff --git a/src/main/java/net/fs/netty/proxy/SocksServerInitializer.java b/src/main/java/net/fs/netty/proxy/SocksServerInitializer.java new file mode 100755 index 0000000..d065999 --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/SocksServerInitializer.java @@ -0,0 +1,34 @@ +package net.fs.netty.proxy; + +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.socks.SocksInitRequestDecoder; +import io.netty.handler.codec.socks.SocksMessageEncoder; +import io.netty.handler.traffic.GlobalTrafficShapingHandler; + +import net.fs.netty.config.Config; + +public final class SocksServerInitializer extends + ChannelInitializer { + + private SocksMessageEncoder socksMessageEncoder; + private SocksServerHandler socksServerHandler; + private GlobalTrafficShapingHandler trafficHandler; + + public SocksServerInitializer(Config config, + GlobalTrafficShapingHandler trafficHandler) { + this.trafficHandler = trafficHandler; + socksMessageEncoder = new SocksMessageEncoder(); + socksServerHandler = new SocksServerHandler(config); + } + + @Override + public void initChannel(SocketChannel socketChannel) throws Exception { + ChannelPipeline p = socketChannel.pipeline(); + p.addLast(new SocksInitRequestDecoder()); + p.addLast(socksMessageEncoder); + p.addLast(socksServerHandler); + p.addLast(trafficHandler); + } +} diff --git a/src/main/java/net/fs/netty/proxy/SocksServerUtils.java b/src/main/java/net/fs/netty/proxy/SocksServerUtils.java new file mode 100755 index 0000000..aa4915e --- /dev/null +++ b/src/main/java/net/fs/netty/proxy/SocksServerUtils.java @@ -0,0 +1,21 @@ +package net.fs.netty.proxy; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; + +public final class SocksServerUtils { + + /** + * Closes the specified channel after all queued write requests are flushed. + */ + public static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener( + ChannelFutureListener.CLOSE); + } + } + + private SocksServerUtils() { + } +} diff --git a/src/main/java/net/fs/rudp/AckListManage.java b/src/main/java/net/fs/rudp/AckListManage.java new file mode 100755 index 0000000..519751e --- /dev/null +++ b/src/main/java/net/fs/rudp/AckListManage.java @@ -0,0 +1,54 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.util.HashMap; +import java.util.Iterator; + +public class AckListManage implements Runnable{ + Thread mainThread; + HashMap taskTable; + public AckListManage(){ + taskTable=new HashMap(); + mainThread=new Thread(this); + mainThread.start(); + } + + synchronized void addAck(ConnectionUDP conn,int sequence){ + if(!taskTable.containsKey(conn.connectId)){ + AckListTask at=new AckListTask(conn); + taskTable.put(conn.connectId, at); + } + AckListTask at=taskTable.get(conn.connectId); + at.addAck(sequence); + } + + synchronized void addLastRead(ConnectionUDP conn){ + if(!taskTable.containsKey(conn.connectId)){ + AckListTask at=new AckListTask(conn); + taskTable.put(conn.connectId, at); + } + } + + public void run(){ + while(true){ + synchronized (this){ + Iterator it=taskTable.keySet().iterator(); + while(it.hasNext()){ + int id=it.next(); + AckListTask at=taskTable.get(id); + at.run(); + } + taskTable.clear(); + taskTable=null; + taskTable=new HashMap(); + } + + try { + Thread.sleep(RUDPConfig.ackListDelay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/net/fs/rudp/AckListTask.java b/src/main/java/net/fs/rudp/AckListTask.java new file mode 100755 index 0000000..9e85ea0 --- /dev/null +++ b/src/main/java/net/fs/rudp/AckListTask.java @@ -0,0 +1,72 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import net.fs.rudp.message.AckListMessage; + +import java.util.ArrayList; +import java.util.HashSet; + + +public class AckListTask { + ConnectionUDP conn; + AckListMessage alm; + int lastRead=0; + ArrayList ackList; + @SuppressWarnings("unchecked") + HashSet set; + AckListTask(ConnectionUDP conn){ + this.conn=conn; + ackList=new ArrayList(); + set=new HashSet(); + } + + synchronized void addAck(int sequence){ + ////#MLog.println("sendACK "+sequence); + if(!set.contains(sequence)){ + ackList.add(sequence); + set.add(sequence); + } + } + + synchronized void run(){ + int offset=0; + int packetLength=RUDPConfig.ackListSum; + int length=ackList.size(); + ////#MLog.println("ffffffffaaaaaaaaa "+length); + int sum=(length/packetLength); + if(length%packetLength!=0){ + sum+=1; + } + if(sum==0){ + sum=1; + } + int len=packetLength; + if(length<=len){ + conn.sender.sendALMessage(ackList); + conn.sender.sendALMessage(ackList); + }else{ + for(int i=0;i nl=copy(offset,len,ackList); + conn.sender.sendALMessage(nl); + conn.sender.sendALMessage(nl); +// conn.sender.sendALMessage(nl); +// conn.sender.sendALMessage(nl); +// conn.sender.sendALMessage(nl); + offset+=packetLength; + ////#MLog.println("fffffffffa "+nl.size()); + if(offset+len>length){ + len=length-(sum-1)*packetLength; + } + } + } + } + + ArrayList copy(int offset,int length,ArrayList ackList){ + ArrayList nl= new ArrayList(); + for(int i=0;i sendRecordTable=new HashMap(); + + + HashMap sendRecordTable_remote=new HashMap(); + + + long startSendTime=0; + + int maxSpeed=(int) (1024*1024); + + int initSpeed=(int) maxSpeed; + + int currentSpeed=initSpeed; + + int lastTime=-1; + + Object syn_timeid=new Object(); + + long sended=0; + + long markTime=0; + + long lastSendPingTime,lastReceivePingTime=System.currentTimeMillis(); + + Random ran=new Random(); + + HashMap pingTable=new HashMap(); + + public int pingDelay=250; + + int clientId_real=-1; + + long needSleep_All,trueSleep_All; + + int maxAcked=0; + + long lastLockTime; + + Route route; + + InetAddress dstIp; + + int dstPort; + + public HashMap connTable=new HashMap(); + + Object syn_connTable=new Object(); + + Object syn_tunTable=new Object(); + + String password; + + public ResendManage resendMange; + + boolean closed=false; + + { + resendMange = new ResendManage(); + } + + ClientControl(Route route,int clientId,InetAddress dstIp,int dstPort){ + this.clientId=clientId; + this.route=route; + this.dstIp=dstIp; + this.dstPort=dstPort; + } + + public void onReceivePacket(DatagramPacket dp){ + byte[] dpData=dp.getData(); + int sType=0; + sType=MessageCheck.checkSType(dp); + int remote_clientId=ByteIntConvert.toInt(dpData, 8); + if(sType==net.fs.rudp.message.MessageType.sType_PingMessage){ + PingMessage pm=new PingMessage(dp); + sendPingMessage2(pm.getPingId(),dp.getAddress(),dp.getPort()); + currentSpeed=pm.getDownloadSpeed()*1024; + }else if(sType==net.fs.rudp.message.MessageType.sType_PingMessage2){ + PingMessage2 pm=new PingMessage2(dp); + lastReceivePingTime=System.currentTimeMillis(); + Long t=pingTable.get(pm.getPingId()); + if(t!=null){ + pingDelay=(int) (System.currentTimeMillis()-t); + String protocal=""; + if(route.isUseTcpTun()){ + protocal="tcp"; + }else { + protocal="udp"; + } + //MLog.println(" receive_ping222: "+pm.getPingId()+" "+new Date()); + MLog.println("delay_"+protocal+" "+pingDelay+"ms "+dp.getAddress().getHostAddress()+":"+dp.getPort()); + } + } + } + + public void sendPacket(DatagramPacket dp) throws IOException{ + + //加密 + + route.sendPacket(dp); + } + + void addConnection(ConnectionUDP conn){ + synchronized (syn_connTable) { + connTable.put(conn.connectId, conn); + } + } + + void removeConnection(ConnectionUDP conn){ + synchronized (syn_connTable) { + connTable.remove(conn.connectId); + } + } + + public void close(){ + closed=true; + route.clientManager.removeClient(clientId); + synchronized (syn_connTable) { + Iterator it=getConnTableIterator(); + while(it.hasNext()){ + final ConnectionUDP conn=connTable.get(it.next()); + if(conn!=null){ + Route.es.execute(new Runnable() { + + @Override + public void run() { + conn.stopnow=true; + conn.destroy(true); + } + }); + + } + } + } + } + + Iterator getConnTableIterator(){ + Iterator it=null; + synchronized (syn_connTable) { + it=new CopiedIterator(connTable.keySet().iterator()); + } + return it; + } + + public void updateClientId(int newClientId){ + clientId_real=newClientId; + sendRecordTable.clear(); + sendRecordTable_remote.clear(); + } + + public void onSendDataPacket(ConnectionUDP conn){ + + } + + public void sendPingMessage(){ + int pingid=Math.abs(ran.nextInt()); + long pingTime=System.currentTimeMillis(); + pingTable.put(pingid, pingTime); + lastSendPingTime=System.currentTimeMillis(); + PingMessage lm=new PingMessage(0,route.localclientId,pingid,Route.localDownloadSpeed,Route.localUploadSpeed); + lm.setDstAddress(dstIp); + lm.setDstPort(dstPort); + try { + sendPacket(lm.getDatagramPacket()); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + public void sendPingMessage2(int pingId,InetAddress dstIp,int dstPort){ + PingMessage2 lm=new PingMessage2(0,route.localclientId,pingId); + lm.setDstAddress(dstIp); + lm.setDstPort(dstPort); + try { + sendPacket(lm.getDatagramPacket()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void onReceivePing(PingMessage pm){ + if(route.mode==2){ + currentSpeed=pm.getDownloadSpeed()*1024; + MLog.println("更新对方速度: "+currentSpeed); + } + } + + SendRecord getSendRecord(int timeId){ + SendRecord record=null; + synchronized (syn_timeid) { + record=sendRecordTable.get(timeId); + if(record==null){ + record=new SendRecord(); + record.setTimeId(timeId); + sendRecordTable.put(timeId, record); + } + } + return record; + } + + public int getCurrentTimeId(){ + long current=System.currentTimeMillis(); + if(startSendTime==0){ + startSendTime=current; + } + int timeId=(int) ((current-startSendTime)/1000); + return timeId; + } + + public int getTimeId(long time){ + int timeId=(int) ((time-startSendTime)/1000); + return timeId; + } + + //纳秒 + public synchronized void sendSleep(long startTime,int length){ + if(route.mode==1){ + currentSpeed=Route.localUploadSpeed; + } + if(sended==0){ + markTime=startTime; + } + sended+=length; + //10K sleep + if(sended>10*1024){ + long needTime=(long) (1000*1000*1000f*sended/currentSpeed); + long usedTime=System.nanoTime()-markTime; + if(usedTime0){ + if(sleepTime<=moreTime){ + sleepTime=0; + trueSleep_All-=sleepTime; + } + } + + long s=needTime/(1000*1000); + int n=(int) (needTime%(1000*1000)); + long t1=System.nanoTime(); + if(sleepTime>0){ + try { + Thread.sleep(s, n); + } catch (InterruptedException e) { + e.printStackTrace(); + } + trueSleep_All+=(System.nanoTime()-t1); + //#MLog.println("sssssssssss "+(trueSleep_All-needSleep_All)/(1000*1000)); + } + ////#MLog.println("sleepb "+sleepTime+" l "+sended+" s "+s+" n "+n+" tt "+(moreTime)); + } + sended=0; + } + + } + + public Object getSynlock() { + return synlock; + } + + public void setSynlock(Object synlock) { + this.synlock = synlock; + } + + public void setClientId(int clientId) { + this.clientId = clientId; + } + + public int getClientId_real() { + return clientId_real; + } + + public void setClientId_real(int clientId_real) { + this.clientId_real = clientId_real; + lastReceivePingTime=System.currentTimeMillis(); + } + + public long getLastSendPingTime() { + return lastSendPingTime; + } + + public void setLastSendPingTime(long lastSendPingTime) { + this.lastSendPingTime = lastSendPingTime; + } + + public long getLastReceivePingTime() { + return lastReceivePingTime; + } + + public void setLastReceivePingTime(long lastReceivePingTime) { + this.lastReceivePingTime = lastReceivePingTime; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/src/main/java/net/fs/rudp/ClientManager.java b/src/main/java/net/fs/rudp/ClientManager.java new file mode 100755 index 0000000..268066e --- /dev/null +++ b/src/main/java/net/fs/rudp/ClientManager.java @@ -0,0 +1,91 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import net.fs.utils.MLog; + +import java.net.InetAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; + + +public class ClientManager { + + HashMap clientTable=new HashMap(); + + Thread mainThread; + + Route route; + + int receivePingTimeout=8*1000; + + int sendPingInterval=1*1000; + + Object syn_clientTable=new Object(); + + ClientManager(Route route){ + this.route=route; + mainThread=new Thread(){ + @Override + public void run(){ + while(true){ + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + scanClientControl(); + } + } + }; + mainThread.start(); + } + + void scanClientControl(){ + Iterator it=getClientTableIterator(); + long current=System.currentTimeMillis(); + //MLog.println("ffffffffffff "+clientTable.size()); + while(it.hasNext()){ + ClientControl cc=clientTable.get(it.next()); + if(cc!=null){ + if(current-cc.getLastReceivePingTime()sendPingInterval){ + cc.sendPingMessage(); + } + }else { + //超时关闭client + MLog.println("超时关闭Client "+cc.dstIp.getHostAddress()+":"+cc.dstPort+" "+new Date()); +// System.exit(0); + synchronized (syn_clientTable) { + cc.close(); + } + } + } + } + } + + void removeClient(int clientId){ + clientTable.remove(clientId); + } + + Iterator getClientTableIterator(){ + Iterator it=null; + synchronized (syn_clientTable) { + it=new CopiedIterator(clientTable.keySet().iterator()); + } + return it; + } + + ClientControl getClientControl(int clientId,InetAddress dstIp,int dstPort){ + ClientControl c=clientTable.get(clientId); + if(c==null){ + c=new ClientControl(route,clientId,dstIp,dstPort); + synchronized (syn_clientTable) { + clientTable.put(clientId, c); + } + } + return c; + } + +} diff --git a/src/main/java/net/fs/rudp/ClientProcessorInterface.java b/src/main/java/net/fs/rudp/ClientProcessorInterface.java new file mode 100755 index 0000000..04d53e8 --- /dev/null +++ b/src/main/java/net/fs/rudp/ClientProcessorInterface.java @@ -0,0 +1,9 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public interface ClientProcessorInterface { + + public void onMapClientClose(); + +} diff --git a/src/main/java/net/fs/rudp/ConnInfo.java b/src/main/java/net/fs/rudp/ConnInfo.java new file mode 100755 index 0000000..cd116da --- /dev/null +++ b/src/main/java/net/fs/rudp/ConnInfo.java @@ -0,0 +1,50 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import net.fs.rudp.StreamPipe.HttpHost; + +public class ConnInfo { + + + String requestHost=null; + + String requestPath=null; + + boolean http=false; + + HttpHost host=null; + + public String getRequestHost() { + return requestHost; + } + + public void setRequestHost(String requestHost) { + this.requestHost = requestHost; + } + + public String getRequestPath() { + return requestPath; + } + + public void setRequestPath(String requestPath) { + this.requestPath = requestPath; + } + + public boolean isHttp() { + return http; + } + + public void setHttp(boolean http) { + this.http = http; + } + + public HttpHost getHost() { + return host; + } + + public void setHost(HttpHost host) { + this.host = host; + } + +} diff --git a/src/main/java/net/fs/rudp/ConnectException.java b/src/main/java/net/fs/rudp/ConnectException.java new file mode 100755 index 0000000..f6e3d7c --- /dev/null +++ b/src/main/java/net/fs/rudp/ConnectException.java @@ -0,0 +1,19 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import net.fs.utils.MLog; + +public class ConnectException extends Exception{ + + private static final long serialVersionUID = 8735513900170495107L; + String message; + ConnectException(String message){ + this.message=message; + } + @Override + public void printStackTrace(){ + //MLog.println("连接异常 "+message); + } + +} diff --git a/src/main/java/net/fs/rudp/ConnectionProcessor.java b/src/main/java/net/fs/rudp/ConnectionProcessor.java new file mode 100755 index 0000000..262b9b4 --- /dev/null +++ b/src/main/java/net/fs/rudp/ConnectionProcessor.java @@ -0,0 +1,9 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + + + +public interface ConnectionProcessor { + abstract void process(final ConnectionUDP conn); +} diff --git a/src/main/java/net/fs/rudp/ConnectionUDP.java b/src/main/java/net/fs/rudp/ConnectionUDP.java new file mode 100755 index 0000000..00cdd3f --- /dev/null +++ b/src/main/java/net/fs/rudp/ConnectionUDP.java @@ -0,0 +1,129 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.util.Random; +import java.util.concurrent.LinkedBlockingQueue; + +public class ConnectionUDP { + public InetAddress dstIp; + public int dstPort; + public Sender sender; + public Receiver receiver; + public UDPOutputStream uos; + public UDPInputStream uis; + long connetionId; + Route route; + int mode; + private boolean connected=true; + long lastLiveTime=System.currentTimeMillis(); + long lastSendLiveTime=0; + + static Random ran=new Random(); + + int connectId; + + ConnectionProcessor connectionProcessor; + + private LinkedBlockingQueue dpBuffer=new LinkedBlockingQueue(); + + public ClientControl clientControl; + + public boolean localClosed=false,remoteClosed=false,destroied=false; + + public boolean stopnow=false; + + public ConnectionUDP(Route ro,InetAddress dstIp,int dstPort,int mode,int connectId,ClientControl clientControl) throws Exception { + this.clientControl=clientControl; + this.route=ro; + this.dstIp=dstIp; + this.dstPort=dstPort; + this.mode=mode; + if(mode==1){ + //MLog.println(" 发起连接RUDP "+dstIp+":"+dstPort+" connectId "+connectId); + }else if(mode==2){ + + //MLog.println(" 接受连接RUDP "+dstIp+":"+dstPort+" connectId "+connectId); + } + this.connectId=connectId; + try { + sender=new Sender(this); + receiver=new Receiver(this); + uos=new UDPOutputStream (this); + uis=new UDPInputStream(this); + if(mode==2){ + ro.createTunnelProcessor().process(this); + } + } catch (Exception e) { + e.printStackTrace(); + connected=false; + route.connTable.remove(connectId); + e.printStackTrace(); + //#MLog.println(" 连接失败RUDP "+connectId); + synchronized(this){ + notifyAll(); + } + throw e; + } + //#MLog.println(" 连接成功RUDP "+connectId); + synchronized(this){ + notifyAll(); + } + } + + public DatagramPacket getPacket(int connectId) throws InterruptedException{ + DatagramPacket dp=(DatagramPacket)dpBuffer.take(); + return dp; + } + + @Override + public String toString(){ + return new String(dstIp+":"+dstPort); + } + + public boolean isConnected(){ + return connected; + } + + public void close_local(){ + if(!localClosed){ + localClosed=true; + if(!stopnow){ + sender.sendCloseMessage_Conn(); + } + destroy(false); + } + } + + public void close_remote() { + if(!remoteClosed){ + remoteClosed=true; + destroy(false); + } + } + + //完全关闭 + public void destroy(boolean force){ + if(!destroied){ + if((localClosed&&remoteClosed)||force){ + destroied=true; + connected=false; + uis.closeStream_Local(); + uos.closeStream_Local(); + sender.destroy(); + receiver.destroy(); + route.removeConnection(this); + clientControl.removeConnection(this); + } + } + } + + public void close_timeout(){ + ////#MLog.println("超时关闭RDP连接"); + } + + void live(){ + lastLiveTime=System.currentTimeMillis(); + } +} diff --git a/src/main/java/net/fs/rudp/Constant.java b/src/main/java/net/fs/rudp/Constant.java new file mode 100755 index 0000000..5a6b764 --- /dev/null +++ b/src/main/java/net/fs/rudp/Constant.java @@ -0,0 +1,20 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public class Constant { + + + public static int code_success=1; + + public static int code_failed=0; + + public static int code_no_port=41; + + public static int code_password_error=42; + + static int protocal_portmap=5755682; + + public static int protocal_socks5proxy=544643; + +} diff --git a/src/main/java/net/fs/rudp/CopiedIterator.java b/src/main/java/net/fs/rudp/CopiedIterator.java new file mode 100755 index 0000000..7c9e171 --- /dev/null +++ b/src/main/java/net/fs/rudp/CopiedIterator.java @@ -0,0 +1,26 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.util.Iterator; +import java.util.LinkedList; + +public class CopiedIterator implements Iterator { + private Iterator iterator = null; + public CopiedIterator(Iterator itr) { + LinkedList list = new LinkedList( ); + while(itr.hasNext( )) { + list.add(itr.next( )); + } + this.iterator = list.iterator( ); + } + public boolean hasNext( ) { + return this.iterator.hasNext( ); + } + public void remove( ) { + throw new UnsupportedOperationException("This is a read-only iterator."); + } + public Object next( ) { + return this.iterator.next( ); + } + } diff --git a/src/main/java/net/fs/rudp/MapSocketPorcessor.java b/src/main/java/net/fs/rudp/MapSocketPorcessor.java new file mode 100755 index 0000000..1054b68 --- /dev/null +++ b/src/main/java/net/fs/rudp/MapSocketPorcessor.java @@ -0,0 +1,211 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + + +public class MapSocketPorcessor implements PipeListener{ + + + Socket srcSocket; + Socket dstSocket; + + public DataInputStream srcIs; + public DataOutputStream dstOs; + public DataInputStream dstIs; + public DataOutputStream srcOs; + + Object srcReadOb=new Object(); + Object dstReadOb=new Object(); + Object dstWriteOb=new Object(); + Object srcWriteOb=new Object(); + + ArrayList srcReadBuffer=new ArrayList(); + ArrayList dstReadBuffer=new ArrayList(); + + Thread srcReadThread; + Thread dstWriteThread; + Thread srcWriteThread; + Thread dstReadThread; + byte[] srcPreRead=new byte[0]; + + int maxDstRead=1; + int maxSrcRead=1; + + boolean isSuperSocket=false; + + boolean dstReadComplete=false; + + boolean srcReadComplete=false; + + boolean srcWriteComplete=false; + + boolean dstWriteComplete=false; + + boolean dstClosed=false; + + boolean srcClosed=false; + + String st=" "; + //String st=" "; + + + String ss=""; + + static int n=0; + + Random ran=new Random(); + + long id; + + static int m=0,a,b; + + boolean closed=false; + + long lastActiveTime=System.currentTimeMillis(); + + //static HashMap procTable=new HashMap(); + + static ExecutorService es; + + MapSocketPorcessor mp; + + Socket socketA,socketB; + + int supserSocketId=-1; + + String requestHost=null; + + static { + es=Executors.newCachedThreadPool(); + } + + public MapSocketPorcessor(){ + + } + + public void setDstSocket(Socket dstSocket){ + this.dstSocket=dstSocket; + } + + public void setId(long id){ + this.id=id; + } + + public boolean isClosed(){ + return closed; + } + + public long getLastActiveTime(){ + return lastActiveTime; + } + + void active(){ + lastActiveTime=System.currentTimeMillis(); + } + + public long getId(){ + return id; + } + + public void closeAll(){ + closeAll(true); + } + + public void closeAll(boolean closeDst){ + //procTable.remove(id); + //Log.println("closeAll AAAAAAAAA"); + if(!closed){ + //Log.println("closeAll BBBBBBBBBB"); + closed=true; + //#MLog.println("MapSocketPorcessor Close"); + try { + srcSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + if(closeDst){ + try { + dstSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + void tryClose(){ + closeAll(); + } + + public void start(){ + Runnable t=new Runnable(){ + public void run(){ + try { + ConnInfo connInfo=new ConnInfo(); + StreamPipe p1=new StreamPipe(connInfo,srcIs,dstOs,10*1024,1000*1024); + StreamPipe p2=new StreamPipe(connInfo,dstIs,srcOs,10*1024,1000*1024); + p1.setType(StreamPipe.type_request); + //p1.addListener(mp); + //p2.addListener(mp); + p1.setSocketA(socketA); + p1.setSocketB(socketB); + p2.setType(StreamPipe.type_respone); + p2.setSocketA(socketA); + p2.setSocketB(socketB); + p1.setSupserSocketId(supserSocketId); + p2.setSupserSocketId(supserSocketId); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + }; + es.execute(t); + } + + public void pipeClose() { + closeAll(); + //pipeclose + } + + public Socket getSocketA() { + return socketA; + } + + public void setSocketA(Socket socketA) { + this.socketA = socketA; + } + + public Socket getSocketB() { + return socketB; + } + + public void setSocketB(Socket socketB) { + this.socketB = socketB; + } + + public int getSupserSocketId() { + return supserSocketId; + } + + public void setSupserSocketId(int supserSocketId) { + this.supserSocketId = supserSocketId; + } + + public String getRequestHost() { + return requestHost; + } + + public void setRequestHost(String requestHost) { + this.requestHost = requestHost; + } + +} diff --git a/src/main/java/net/fs/rudp/MessageInterface.java b/src/main/java/net/fs/rudp/MessageInterface.java new file mode 100755 index 0000000..4bc4e25 --- /dev/null +++ b/src/main/java/net/fs/rudp/MessageInterface.java @@ -0,0 +1,12 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.net.DatagramPacket; + +public interface MessageInterface { + public int getVer(); + public int getSType(); + public DatagramPacket getDatagramPacket(); +} + diff --git a/src/main/java/net/fs/rudp/PipeListener.java b/src/main/java/net/fs/rudp/PipeListener.java new file mode 100755 index 0000000..5d2a253 --- /dev/null +++ b/src/main/java/net/fs/rudp/PipeListener.java @@ -0,0 +1,9 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public interface PipeListener { + + void pipeClose(); + +} diff --git a/src/main/java/net/fs/rudp/RUDPConfig.java b/src/main/java/net/fs/rudp/RUDPConfig.java new file mode 100755 index 0000000..e8ac6f1 --- /dev/null +++ b/src/main/java/net/fs/rudp/RUDPConfig.java @@ -0,0 +1,27 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public class RUDPConfig { + + public static short protocal_ver=0; + + public static int packageSize=800; + //public static int packageSize=1024; + + public static boolean twice_udp=false; + + public static boolean twice_tcp=false; + + public static int maxWin = 5*1024; + + public static int ackListDelay = 5; + public static int ackListSum = 300; + + public static boolean double_send_start = true; + + public static int reSendDelay_min = 100; + public static float reSendDelay = 0.37f; + public static int reSendTryTimes = 10; + +} diff --git a/src/main/java/net/fs/rudp/ReceivePingException.java b/src/main/java/net/fs/rudp/ReceivePingException.java new file mode 100755 index 0000000..da3f040 --- /dev/null +++ b/src/main/java/net/fs/rudp/ReceivePingException.java @@ -0,0 +1,18 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public class ReceivePingException extends Exception{ + /** + * + */ + private static final long serialVersionUID = -5199731243611486228L; + String message; + ReceivePingException(String message){ + this.message=message; + } + @Override + public void printStackTrace(){ + //#MLog.println("Ping寮傚父 "+message); + } +} diff --git a/src/main/java/net/fs/rudp/Receiver.java b/src/main/java/net/fs/rudp/Receiver.java new file mode 100755 index 0000000..9b82191 --- /dev/null +++ b/src/main/java/net/fs/rudp/Receiver.java @@ -0,0 +1,263 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import net.fs.rudp.message.AckListMessage; +import net.fs.rudp.message.CloseMessage_Conn; +import net.fs.rudp.message.CloseMessage_Stream; +import net.fs.rudp.message.DataMessage; +import net.fs.utils.MessageCheck; + +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; + + +public class Receiver { + ConnectionUDP conn; + Sender sender; + public InetAddress dstIp; + public int dstPort; + HashMap receiveTable=new HashMap(); + int lastRead=-1; + int lastReceive=-1; + Object availOb=new Object(); + + boolean isReady=false; + Object readyOb=new Object(); + byte[] b4=new byte[4]; + int lastRead1=0; + int maxWinR=10; + int lastRead2=-1; + UDPInputStream uis; + + float availWin=RUDPConfig.maxWin; + + int currentRemoteTimeId; + + int closeOffset; + + boolean streamClose=false; + + boolean reveivedClose=false; + + static int m=0,x,x2,c; + + boolean b=false,b2; + + public int nw; + + long received; + + Receiver(ConnectionUDP conn){ + this.conn=conn; + uis=new UDPInputStream(conn); + this.sender=conn.sender; + this.dstIp=conn.dstIp; + this.dstPort=conn.dstPort; + } + + //接收流数据 + public byte[] receive() throws ConnectException { + DataMessage me=null; + if(conn.isConnected()){ + me=receiveTable.get(lastRead+1); + synchronized (availOb){ + if(me==null){ + //MLog.println("等待中 "+conn.connectId+" "+(lastRead+1)); + + try { + availOb.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + me=receiveTable.get(lastRead+1); + //MLog.println("等待完成aaa "+conn.connectId+" "+(lastRead+1)); + } + } + + }else{ + //throw new ConnectException("连接未建立"); + throw new ConnectException(""); + } + + if(!streamClose){ + checkCloseOffset_Remote(); + if(me==null){ + //throw new ConnectException("连接已断开"); + throw new ConnectException(""); + }else { + } + conn.sender.sendLastReadDelay(); + + lastRead++; + synchronized (availOb){ + receiveTable.remove(me.getSequence()); + } + + received+=me.getData().length; + //System.out.println("received "+received/1024/1024+"MB"); + return me.getData(); + }else{ + //throw new ConnectException("连接已断开"); + throw new ConnectException(""); + } + } + + public void onReceivePacket(DatagramPacket dp){ + DataMessage me; + if(dp!=null){ + if(conn.isConnected()){ + int ver=MessageCheck.checkVer(dp); + int sType=MessageCheck.checkSType(dp); + if(ver==RUDPConfig.protocal_ver){ + conn.live(); + if(sType==net.fs.rudp.message.MessageType.sType_DataMessage){ + me=new DataMessage(dp); + int timeId=me.getTimeId(); + SendRecord record=conn.clientControl.sendRecordTable_remote.get(timeId); + if(record==null){ + record=new SendRecord(); + record.setTimeId(timeId); + conn.clientControl.sendRecordTable_remote.put(timeId, record); + } + record.addSended(me.getData().length); + + if(timeId>currentRemoteTimeId){ + currentRemoteTimeId=timeId; + } + + int sequence=me.getSequence(); + + conn.sender.sendAckDelay(me.getSequence()); + if(sequence>lastRead){ + synchronized (availOb){ + receiveTable.put(sequence, me); + if(receiveTable.containsKey(lastRead+1)){ + availOb.notify(); + } + } + } + }else if(sType==net.fs.rudp.message.MessageType.sType_AckListMessage){ + AckListMessage alm=new AckListMessage(dp); + int lastRead3=alm.getLastRead(); + if(lastRead3>lastRead2){ + lastRead2=lastRead3; + } + ArrayList ackList=alm.getAckList(); + + for(int i=0;irc1.getAckedSize()){ + rc1.setAckedSize(alm.getS1()); + } + } + + SendRecord rc2=conn.clientControl.getSendRecord(alm.getR2()); + if(rc2!=null){ + if(alm.getS2()>rc2.getAckedSize()){ + rc2.setAckedSize(alm.getS2()); + } + } + + SendRecord rc3=conn.clientControl.getSendRecord(alm.getR3()); + if(rc3!=null){ + if(alm.getS3()>rc3.getAckedSize()){ + rc3.setAckedSize(alm.getS3()); + } + } + + if(checkWin()){ + conn.sender.play(); + } + }else if(sType==net.fs.rudp.message.MessageType.sType_CloseMessage_Stream){ + CloseMessage_Stream cm=new CloseMessage_Stream(dp); + reveivedClose=true; + int n=cm.getCloseOffset(); + closeStream_Remote(n); + }else if(sType==net.fs.rudp.message.MessageType.sType_CloseMessage_Conn){ + CloseMessage_Conn cm2=new CloseMessage_Conn(dp); + conn.close_remote(); + }else{ + ////#MLog.println("未处理数据包 "+sType); + } + } + + } + } + + } + + public void destroy(){ + //#MLog.println("destroy destroy destroy"); + synchronized (availOb) { + receiveTable.clear(); + } + } + + boolean checkWin(){ + nw=conn.sender.sendOffset-lastRead2; + boolean b=false; + if(nw=closeOffset-1){ + streamClose=true; + synchronized (availOb){ + availOb.notifyAll(); + } + conn.sender.closeStream_Remote(); + } + } + } + } + + void closeStream_Local(){ + if(!streamClose){ + c++; + streamClose=true; + synchronized (availOb){ + availOb.notifyAll(); + } + conn.sender.closeStream_Local(); + } + } + + public int getCurrentTimeId() { + return currentRemoteTimeId; + } + + public void setCurrentTimeId(int currentTimeId) { + this.currentRemoteTimeId = currentTimeId; + } + + + public int getCloseOffset() { + return closeOffset; + } + + + public void setCloseOffset(int closeOffset) { + this.closeOffset = closeOffset; + } + +} diff --git a/src/main/java/net/fs/rudp/ResendItem.java b/src/main/java/net/fs/rudp/ResendItem.java new file mode 100755 index 0000000..e27ee31 --- /dev/null +++ b/src/main/java/net/fs/rudp/ResendItem.java @@ -0,0 +1,56 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public class ResendItem { + + int count; + + ConnectionUDP conn; + + int sequence; + + long resendTime; + + ResendItem(ConnectionUDP conn,int sequence){ + this.conn=conn; + this.sequence=sequence; + } + + void addCount(){ + count++; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public ConnectionUDP getConn() { + return conn; + } + + public void setConn(ConnectionUDP conn) { + this.conn = conn; + } + + public int getSequence() { + return sequence; + } + + public void setSequence(int sequence) { + this.sequence = sequence; + } + + public long getResendTime() { + return resendTime; + } + + public void setResendTime(long resendTime) { + this.resendTime = resendTime; + } + +} diff --git a/src/main/java/net/fs/rudp/ResendManage.java b/src/main/java/net/fs/rudp/ResendManage.java new file mode 100755 index 0000000..60bfd85 --- /dev/null +++ b/src/main/java/net/fs/rudp/ResendManage.java @@ -0,0 +1,78 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.util.concurrent.LinkedBlockingQueue; + + +public class ResendManage implements Runnable{ + + boolean haveTask=false; + Object signalOb=new Object(); + Thread mainThread; + long vTime=0; + long lastReSendTime; + + LinkedBlockingQueue taskList=new LinkedBlockingQueue(); + + public ResendManage(){ + Route.es.execute(this); + } + + public void addTask(final ConnectionUDP conn,final int sequence){ + ResendItem ri=new ResendItem(conn, sequence); + ri.setResendTime(getNewResendTime(conn)); + taskList.add(ri); + } + + long getNewResendTime(ConnectionUDP conn){ + int delayAdd=conn.clientControl.pingDelay+(int) ((float)conn.clientControl.pingDelay*RUDPConfig.reSendDelay); + if(delayAdd0){ + Thread.sleep(sleepTime); + } + ri.addCount(); + + if(ri.conn.sender.getDataMessage(ri.sequence)!=null){ + + if(!ri.conn.stopnow){ + //多线程重发容易内存溢出 +// Route.es.execute(new Runnable() { +// +// @Override +// public void run() { +// ri.conn.sender.reSend(ri.sequence,ri.getCount()); +// } +// +// }); + ri.conn.sender.reSend(ri.sequence,ri.getCount()); + } + + } + if(ri.getCount() connTable; + Route route; + Thread mainThread; + Thread reveiveThread; + + public static ThreadPoolExecutor es; + + public AckListManage delayAckManage; + + Object syn_ds2Table=new Object(); + + Object syn_tunTable=new Object(); + + Random ran=new Random(); + + public int localclientId=Math.abs(ran.nextInt()); + + LinkedBlockingQueue packetBuffer=new LinkedBlockingQueue(); + + public static int mode_server=2; + + public static int mode_client=1; + + public int mode=mode_client;//1客户端,2服务端 + + String pocessName=""; + + HashSet setedTable=new HashSet(); + + static int vv; + + HashSet closedTable=new HashSet(); + + public static int localDownloadSpeed,localUploadSpeed; + + ClientManager clientManager; + + HashSet pingTable=new HashSet(); + + public CapEnv capEnv=null; + + public ClientControl lastClientControl; + + public boolean useTcpTun=true; + + public HashMap contentTable=new HashMap(); + + private static List listenerList=new Vector(); + + { + + delayAckManage = new AckListManage(); + } + + static{ + SynchronousQueue queue = new SynchronousQueue(); + ThreadPoolExecutor executor = new ThreadPoolExecutor(100, Integer.MAX_VALUE, 10*1000, TimeUnit.MILLISECONDS, queue); + es=executor; + } + + public Route(String pocessName,short routePort,int mode2,boolean tcp,boolean tcpEnvSuccess) throws Exception{ + + this.mode=mode2; + useTcpTun=tcp; + this.pocessName=pocessName; + if(useTcpTun){ + if(mode==2){ + //服务端 + VDatagramSocket d=new VDatagramSocket(routePort); + d.setClient(false); + try { + capEnv=new CapEnv(false,tcpEnvSuccess); + capEnv.setListenPort(routePort); + capEnv.init(); + } catch (Exception e) { + //e.printStackTrace(); + throw e; + } + d.setCapEnv(capEnv); + + ds=d; + }else { + //客户端 + VDatagramSocket d=new VDatagramSocket(); + d.setClient(true); + try { + capEnv=new CapEnv(true,tcpEnvSuccess); + capEnv.init(); + } catch (Exception e) { + //e.printStackTrace(); + throw e; + } + d.setCapEnv(capEnv); + + ds=d; + } + }else { + if(mode==2){ + MLog.info("Listen udp port: "+CapEnv.toUnsigned(routePort)); + ds=new DatagramSocket(CapEnv.toUnsigned(routePort)); + }else { + ds=new DatagramSocket(); + } + } + + connTable=new HashMap(); + clientManager=new ClientManager(this); + reveiveThread=new Thread(){ + @Override + public void run(){ + while(true){ + //byte[] b=new byte[2048]; + byte[] b=new byte[1500]; + DatagramPacket dp=new DatagramPacket(b,b.length); + try { + ds.receive(dp); + //MLog.println("接收Socket请求"+dp.getAddress()); + packetBuffer.add(dp); + } catch (IOException e) { + e.printStackTrace(); + try { + Thread.sleep(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + continue; + } + } + } + }; + reveiveThread.start(); + + mainThread=new Thread(){ + public void run() { + while(true){ + DatagramPacket dp=null; + try { + dp = packetBuffer.take(); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + if(dp==null){ + continue; + } + long t1=System.currentTimeMillis(); + byte[] dpData=dp.getData(); + + int sType=0; + if(dp.getData().length<4){ + return; + } + sType=MessageCheck.checkSType(dp); + //MLog.println("route receive MessageType111#"+sType+" "+dp.getAddress()+":"+dp.getPort()); + if(dp!=null){ + + final int connectId=ByteIntConvert.toInt(dpData, 4); + int remote_clientId=ByteIntConvert.toInt(dpData, 8); + + if(closedTable.contains(connectId)&&connectId!=0){ + //MLog.println("忽略已关闭连接包 "+connectId); + continue; + } + + if(sType==net.fs.rudp.message.MessageType.sType_PingMessage + ||sType==net.fs.rudp.message.MessageType.sType_PingMessage2){ + ClientControl clientControl=null; + if(mode==2){ + //发起 + clientControl=clientManager.getClientControl(remote_clientId,dp.getAddress(),dp.getPort()); + }else if(mode==1){ + //接收 + String key=dp.getAddress().getHostAddress()+":"+dp.getPort(); + int sim_clientId=Math.abs(key.hashCode()); + clientControl=clientManager.getClientControl(sim_clientId,dp.getAddress(),dp.getPort()); + } + clientControl.onReceivePacket(dp); + }else { + //发起 + if(mode==1){ + if(!setedTable.contains(remote_clientId)){ + String key=dp.getAddress().getHostAddress()+":"+dp.getPort(); + int sim_clientId=Math.abs(key.hashCode()); + ClientControl clientControl=clientManager.getClientControl(sim_clientId,dp.getAddress(),dp.getPort()); + if(clientControl.getClientId_real()==-1){ + clientControl.setClientId_real(remote_clientId); + //#MLog.println("首次设置clientId "+remote_clientId); + }else { + if(clientControl.getClientId_real()!=remote_clientId){ + //#MLog.println("服务端重启更新clientId "+sType+" "+clientControl.getClientId_real()+" new: "+remote_clientId); + clientControl.updateClientId(remote_clientId); + } + } + //#MLog.println("cccccc "+sType+" "+remote_clientId); + setedTable.add(remote_clientId); + } + } + + + //udp connection + if(mode==2){ + //接收 + try { + getConnection2(dp.getAddress(),dp.getPort(),connectId,remote_clientId); + } catch (Exception e) { + e.printStackTrace(); + } + } + + final ConnectionUDP ds3=connTable.get(connectId); + if(ds3!=null){ + final DatagramPacket dp2=dp; + ds3.receiver.onReceivePacket(dp2); + if(sType==MessageType.sType_DataMessage){ + TrafficEvent event=new TrafficEvent("",ran.nextLong(),dp.getLength(),TrafficEvent.type_downloadTraffic); + fireEvent(event); + } + } + + } + } + } + } + }; + mainThread.start(); + + } + + public static void addTrafficlistener(Trafficlistener listener){ + listenerList.add(listener); + } + + static void fireEvent(TrafficEvent event){ + for(Trafficlistener listener:listenerList){ + int type=event.getType(); + if(type==TrafficEvent.type_downloadTraffic){ + listener.trafficDownload(event); + }else if(type==TrafficEvent.type_uploadTraffic){ + listener.trafficUpload(event); + } + } + } + + public void sendPacket(DatagramPacket dp) throws IOException{ + ds.send(dp); + } + + public ConnectionProcessor createTunnelProcessor(){ + ConnectionProcessor o=null; + try { + Class onwClass = Class.forName(pocessName); + o = (ConnectionProcessor) onwClass.newInstance(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return o; + } + + void removeConnection(ConnectionUDP conn){ + synchronized (syn_ds2Table){ + closedTable.add(conn.connectId); + connTable.remove(conn.connectId); + } + } + + //接收连接 + public ConnectionUDP getConnection2(InetAddress dstIp,int dstPort,int connectId,int clientId) throws Exception{ + ConnectionUDP conn=connTable.get(connectId); + if(conn==null){ + ClientControl clientControl=clientManager.getClientControl(clientId,dstIp,dstPort); + conn=new ConnectionUDP(this,dstIp,dstPort,2,connectId,clientControl); + synchronized (syn_ds2Table){ + connTable.put(connectId, conn); + } + clientControl.addConnection(conn); + } + return conn; + } + + //发起连接 + public ConnectionUDP getConnection(String address,int dstPort,String password) throws Exception{ + InetAddress dstIp=InetAddress.getByName(address); + int connectId=Math.abs(ran.nextInt()); + String key=dstIp.getHostAddress()+":"+dstPort; + int remote_clientId=Math.abs(key.hashCode()); + ClientControl clientControl=clientManager.getClientControl(remote_clientId,dstIp,dstPort); + clientControl.setPassword(password); + ConnectionUDP conn=new ConnectionUDP(this,dstIp,dstPort,1,connectId,clientControl); + synchronized (syn_ds2Table){ + connTable.put(connectId, conn); + } + clientControl.addConnection(conn); + lastClientControl=clientControl; + return conn; + } + + public boolean isUseTcpTun() { + return useTcpTun; + } + + public void setUseTcpTun(boolean useTcpTun) { + this.useTcpTun = useTcpTun; + } + +} + + diff --git a/src/main/java/net/fs/rudp/SendRecord.java b/src/main/java/net/fs/rudp/SendRecord.java new file mode 100755 index 0000000..64e058d --- /dev/null +++ b/src/main/java/net/fs/rudp/SendRecord.java @@ -0,0 +1,114 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public class SendRecord { + + int sendSize,sendSize_First; + + int sendCount; + + int ackedSize; + + int timeId; + + int speed; + + boolean speedRecored=false; + + int resended; + + SendRecord(){ + + } + + float getDropRate(){ + int droped=getSendSize()-getAckedSize(); + if(droped<0){ + droped=0; + } + float dropRate=0; + if(getSendSize()>0){ + dropRate=(float)droped/getSendSize(); + } + return dropRate; + } + + float getResendRate(){ + float resendRate=0; + if(getSendSize_First()>0){ + resendRate=(float)getResended()/getSendSize_First(); + } + return resendRate; + } + + void addResended(int size){ + resended+=size; + } + + void addSended(int size){ + sendCount++; + sendSize+=size; + } + + void addSended_First(int size){ + sendSize_First+=size; + } + + public int getSendSize() { + return sendSize; + } + + public int getSendCount() { + return sendCount; + } + + public int getAckedSize() { + return ackedSize; + } + + //接收到的数据大小 + public void setAckedSize(int ackedSize) { + if(ackedSize>this.ackedSize){ + this.ackedSize = ackedSize; + } + } + + public int getTimeId() { + return timeId; + } + + public void setTimeId(int timeId) { + this.timeId = timeId; + } + + public int getSpeed() { + return speed; + } + + public void setSpeed(int speed) { + this.speed = speed; + speedRecored=true; + } + + public boolean isSpeedRecored(){ + return speedRecored; + } + + public int getResended() { + return resended; + } + + public void setResended(int resended) { + this.resended = resended; + } + + public int getSendSize_First() { + return sendSize_First; + } + + public void setSendSize_First(int sendSize_First) { + this.sendSize_First = sendSize_First; + } + +} diff --git a/src/main/java/net/fs/rudp/Sender.java b/src/main/java/net/fs/rudp/Sender.java new file mode 100755 index 0000000..84b0829 --- /dev/null +++ b/src/main/java/net/fs/rudp/Sender.java @@ -0,0 +1,302 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import net.fs.rudp.message.AckListMessage; +import net.fs.rudp.message.CloseMessage_Conn; +import net.fs.rudp.message.CloseMessage_Stream; +import net.fs.rudp.message.DataMessage; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Random; + +public class Sender { + DataMessage me2=null; + int interval; + + public int sum=0; + int sleepTime=100; + ConnectionUDP conn; + Receiver receiver=null; + boolean bussy=false; + Object bussyOb=new Object(); + boolean isHave=false; + public HashMap sendTable=new HashMap(); + boolean isReady=false; + Object readyOb=new Object(); + Object winOb=new Object(); + public InetAddress dstIp; + public int dstPort; + public int sequence=0; + int sendOffset=-1; + boolean pause=false; + int unAckMin=0; + int unAckMax=-1; + int sendSum=0; + int reSendSum=0; + UDPOutputStream uos; + int sw=0; + + static Random ran=new Random(); + + long lastSendTime=-1; + + boolean closed=false; + + boolean streamClosed=false; + + static int s=0; + + Object syn_send_table=new Object(); + + HashMap unAckTable=new HashMap(); + + Sender(ConnectionUDP conn){ + this.conn=conn; + uos=new UDPOutputStream (conn); + receiver=conn.receiver; + this.dstIp=conn.dstIp; + this.dstPort=conn.dstPort; + } + + void sendData(byte[] data,int offset,int length) throws ConnectException, InterruptedException{ + int packetLength=RUDPConfig.packageSize; + int sum=(length/packetLength); + if(length%packetLength!=0){ + sum+=1; + } + if(sum==0){ + sum=1; + } + int len=packetLength; + if(length<=len){ + sw++; + sendNata(data,0,length); + sw--; + }else{ + for(int i=0;ilength){ + len=length-(sum-1)*packetLength; + } + } + } + } + + void sendNata(byte[] data,int offset,int length) throws ConnectException, InterruptedException{ + + if(!closed){ + if(!streamClosed){ + DataMessage me=new DataMessage(sequence,data,0,(short) length,conn.connectId,conn.route.localclientId); + me.setDstAddress(dstIp); + me.setDstPort(dstPort); + synchronized (syn_send_table) { + sendTable.put(me.getSequence(),me); + } + + synchronized (winOb){ + if(!conn.receiver.checkWin()){ + try { + winOb.wait(); + } catch (InterruptedException e) { + throw e; + } + } + } + + boolean twice=false; + if(RUDPConfig.twice_tcp){ + twice=true; + } + if(RUDPConfig.double_send_start){ + if(me.getSequence()<=5){ + twice=true; + } + } + sendDataMessage(me,false,twice,true); + lastSendTime=System.currentTimeMillis(); + sendOffset++; + s+=me.getData().length; + conn.clientControl.resendMange.addTask(conn, sequence); + sequence++;//必须放最后 + }else{ + throw new ConnectException("RDP连接已断开sendData"); + } + }else{ + throw new ConnectException("RDP连接已经关闭"); + } + + } + + public void closeStream_Local(){ + if(!streamClosed){ + streamClosed=true; + conn.receiver.closeStream_Local(); + if(!conn.stopnow){ + sendCloseMessage_Stream(); + } + } + } + + public void closeStream_Remote(){ + if(!streamClosed){ + streamClosed=true; + } + } + + void sendDataMessage(DataMessage me,boolean resend,boolean twice,boolean block){ + synchronized (conn.clientControl.getSynlock()) { + long startTime=System.nanoTime(); + long t1=System.currentTimeMillis(); + conn.clientControl.onSendDataPacket(conn); + + int timeId=conn.clientControl.getCurrentTimeId(); + + me.create(timeId); + + SendRecord record_current=conn.clientControl.getSendRecord(timeId); + if(!resend){ + //第一次发,修改当前时间记录 + me.setFirstSendTimeId(timeId); + me.setFirstSendTime(System.currentTimeMillis()); + record_current.addSended_First(me.getData().length); + record_current.addSended(me.getData().length); + }else { + //重发,修改第一次发送时间记录 + SendRecord record=conn.clientControl.getSendRecord(me.getFirstSendTimeId()); + record.addResended(me.getData().length); + record_current.addSended(me.getData().length); + } + + try { + sendSum++; + sum++; + unAckMax++; + + long t=System.currentTimeMillis(); + send(me.getDatagramPacket()); + + if(twice){ + send(me.getDatagramPacket());//发两次 + } + if(block){ + conn.clientControl.sendSleep(startTime, me.getData().length); + } + TrafficEvent event=new TrafficEvent("",ran.nextLong(),me.getData().length,TrafficEvent.type_uploadTraffic); + Route.fireEvent(event); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + void sendAckDelay(int ackSequence){ + conn.route.delayAckManage.addAck(conn, ackSequence); + } + + void sendLastReadDelay(){ + conn.route.delayAckManage.addLastRead(conn); + } + + DataMessage getDataMessage(int sequence){ + return sendTable.get(sequence); + } + + public void reSend(int sequence,int count){ + if(sendTable.containsKey(sequence)){ + DataMessage dm=sendTable.get(sequence); + if(dm!=null){ + sendDataMessage(dm,true,false,true); + } + } + } + + public void destroy(){ + synchronized (syn_send_table) { + sendTable.clear(); + } + } + + //删除后不会重发 + void removeSended_Ack(int sequence){ + synchronized (syn_send_table) { + DataMessage dm=sendTable.remove(sequence); + } + } + + void play(){ + synchronized (winOb){ + winOb.notifyAll(); + } + } + + void close(){ + synchronized (winOb){ + closed=true; + winOb.notifyAll(); + } + } + + void sendCloseMessage_Stream(){ + CloseMessage_Stream cm=new CloseMessage_Stream(conn.connectId,conn.route.localclientId,sequence); + cm.setDstAddress(dstIp); + cm.setDstPort(dstPort); + try { + send(cm.getDatagramPacket()); + } catch (IOException e) { + e.printStackTrace(); + } + try { + send(cm.getDatagramPacket()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + void sendCloseMessage_Conn(){ + CloseMessage_Conn cm=new CloseMessage_Conn(conn.connectId,conn.route.localclientId); + cm.setDstAddress(dstIp); + cm.setDstPort(dstPort); + try { + send(cm.getDatagramPacket()); + } catch (IOException e) { + e.printStackTrace(); + } + try { + send(cm.getDatagramPacket()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + void sendALMessage(ArrayList ackList){ + int currentTimeId=conn.receiver.getCurrentTimeId(); + AckListMessage alm=new AckListMessage(conn.connetionId,ackList,conn.receiver.lastRead,conn + .clientControl.sendRecordTable_remote,currentTimeId, + conn.connectId,conn.route.localclientId); + alm.setDstAddress(dstIp); + alm.setDstPort(dstPort); + try { + send(alm.getDatagramPacket()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + void send(DatagramPacket dp) throws IOException { + sendPacket(dp,conn.connectId); + } + + public void sendPacket(DatagramPacket dp,Integer di) throws IOException{ + conn.clientControl.sendPacket(dp); + } + +} diff --git a/src/main/java/net/fs/rudp/StreamPipe.java b/src/main/java/net/fs/rudp/StreamPipe.java new file mode 100755 index 0000000..dc1b764 --- /dev/null +++ b/src/main/java/net/fs/rudp/StreamPipe.java @@ -0,0 +1,277 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.Semaphore; + + +public class StreamPipe { + + DataInputStream is; + + DataOutputStream os; + + List listenerList; + + boolean closed=false; + + int maxLen=2000; + + long lastResetTime; + + int maxSpeed=100*1024*1024; + + int port=0; + + int limiteConnectTime; + + String userId=""; + + byte[] preReadData; + + int preReadDataLength; + + Socket socketA,socketB; + + boolean writing=false; + + int BUF_SIZE; + + ArrayList dataList=new ArrayList(); + + Semaphore semp_have_data=new Semaphore(0); + + int cachedSize=0; + + int supserSocketId=-1; + + static int type_request=1; + + static int type_respone=2; + + int type=0; + + ConnInfo connInfo; + + public StreamPipe(ConnInfo connInfo,final DataInputStream is,final DataOutputStream os,final int BUF_SIZE,final int maxSpeed){ + this(connInfo,is, os, BUF_SIZE, maxSpeed, null, 0); + } + + public StreamPipe(ConnInfo ci,final DataInputStream is,final DataOutputStream os,int BUF_SIZE1,final int maxSpeed,final byte[] preReadData,final int preReadDataLength){ + connInfo=ci; + listenerList=new Vector(); + this.maxSpeed=maxSpeed; + this.preReadData=preReadData; + BUF_SIZE=BUF_SIZE1; + if(maxSpeed<=50*1024){ + //BUF_SIZE=100; + } + Runnable thread=new Runnable(){ + + int count=0; + public void run(){ + byte[] data=new byte[BUF_SIZE]; + int len=0; + try { + if(preReadData!=null){ +// String string=new String(preReadData,0,preReadDataLength); +// Log.println("写预读111 "+string); + try { + os.write(preReadData,0,preReadDataLength); + } catch (IOException e) { + e.printStackTrace(); + return; + } +// Log.println("写预读222 "); + } + //Log.println("pipe发送 111 "+supserSocketId+" "); + boolean parsed=false; + try { + while((len=is.read(data))>0){ + try { + os.write(data,0,len); + } catch (IOException e) { + //e.printStackTrace(); + break; + } + + } + } catch (IOException e) { + //e.printStackTrace(); + } + }finally{ + close(); + } + } + }; + Route.es.execute(thread); + } + + void close(){ + if(!closed){ + closed=true; + try { + Thread.sleep(500); + } catch (InterruptedException e1) { + //e1.printStackTrace(); + } + + if(socketA!=null){ + Route.es.execute(new Runnable() { + + public void run() { + try { + socketA.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + }); + + } + + + if(socketB!=null){ + + Route.es.execute(new Runnable() { + + public void run() { + try { + socketB.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + }); + + } + fireClose(); + } + } + + class HttpHost{ + String address; + int port=80; + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + public int getPort() { + return port; + } + public void setPort(int port) { + this.port = port; + } + + } + + HttpHost readHost(String data){ + HttpHost hh=new HttpHost(); + String host=null; + data=data.replaceAll("\r", ""); + data=data.replaceAll(" ", ""); + String[] ls=data.split("\n"); + for(String l:ls){ + if(l.startsWith("Host:")){ + String s1=l.substring(5); + int index2=s1.indexOf(":"); + if(index2>-1){ + int port=Integer.parseInt(s1.substring(index2+1)); + hh.setPort(port); + s1=s1.substring(0,index2); + } + host=s1; + hh.setAddress(host); + ////#MLog.println("ddd "+s1); + } + } + return hh; + } + + public void addListener(PipeListener listener){ + listenerList.add(listener); + } + + void fireClose(){ + //Log.println("StreamPipe关闭 fireClose111 "+listenerList.size()); + for(PipeListener listener:listenerList){ + //Log.println("StreamPipe关闭 fireClose222"); + listener.pipeClose(); + } + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public int getLimiteConnectTime() { + return limiteConnectTime; + } + + public void setLimiteConnectTime(int limiteConnectTime) { + this.limiteConnectTime = limiteConnectTime; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Socket getSocketA() { + return socketA; + } + + public void setSocketA(Socket socketA) { + this.socketA = socketA; + } + + public Socket getSocketB() { + return socketB; + } + + public void setSocketB(Socket socketB) { + this.socketB = socketB; + } + + public int getSupserSocketId() { + return supserSocketId; + } + + public void setSupserSocketId(int supserSocketId) { + this.supserSocketId = supserSocketId; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public ConnInfo getConnInfo() { + return connInfo; + } + + public void setConnInfo(ConnInfo connInfo) { + this.connInfo = connInfo; + } + +} diff --git a/src/main/java/net/fs/rudp/TrafficEvent.java b/src/main/java/net/fs/rudp/TrafficEvent.java new file mode 100755 index 0000000..b848b41 --- /dev/null +++ b/src/main/java/net/fs/rudp/TrafficEvent.java @@ -0,0 +1,60 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public class TrafficEvent { + + long eventId; + + int traffic; + + public static int type_downloadTraffic=10; + + public static int type_uploadTraffic=11; + + int type=type_downloadTraffic; + + String userId; + + TrafficEvent(long eventId,int traffic,int type){ + this(null,eventId,traffic,type); + } + + public TrafficEvent(String userId,long eventId,int traffic,int type){ + this.userId=userId; + this.eventId=eventId; + this.traffic=traffic; + this.type=type; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public int getType() { + return type; + } + + public long getEventId() { + return eventId; + } + + public void setEventId(long eventId) { + this.eventId = eventId; + } + + public int getTraffic() { + return traffic; + } + + public void setTraffic(int traffic) { + this.traffic = traffic; + } + + + +} diff --git a/src/main/java/net/fs/rudp/Trafficlistener.java b/src/main/java/net/fs/rudp/Trafficlistener.java new file mode 100755 index 0000000..990c9f9 --- /dev/null +++ b/src/main/java/net/fs/rudp/Trafficlistener.java @@ -0,0 +1,12 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +public interface Trafficlistener { + + public void trafficDownload(TrafficEvent event); + + + public void trafficUpload(TrafficEvent event); + +} diff --git a/src/main/java/net/fs/rudp/UDPInputStream.java b/src/main/java/net/fs/rudp/UDPInputStream.java new file mode 100755 index 0000000..72a16c2 --- /dev/null +++ b/src/main/java/net/fs/rudp/UDPInputStream.java @@ -0,0 +1,46 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.rudp; + +import java.net.DatagramSocket; +import java.net.InetAddress; + +public class UDPInputStream { + + DatagramSocket ds; + InetAddress dstIp; + int dstPort; + Receiver receiver; + + boolean streamClosed=false; + + ConnectionUDP conn; + + UDPInputStream(ConnectionUDP conn){ + this.conn=conn; + receiver=conn.receiver; + } + + public int read(byte[] b, int off, int len) throws ConnectException, InterruptedException { + byte[] b2=null; + b2 = read2(); + if(len ackList; + byte[] dpData=null; + int lastRead; + + int r1,r2,r3,s1,s2,s3; + + @SuppressWarnings("unchecked") + public AckListMessage(long connId,ArrayList ackList,int lastRead, + HashMap sendRecordTable,int timeId, + int connectId,int clientId){ + this.clientId=clientId; + this.connectId=connectId; + this.ackList=ackList; + this.lastRead=lastRead; + int len1=4+4+10+4*ackList.size(); + dpData=new byte[len1+24+9]; + sType=MessageType.sType_AckListMessage; + ByteShortConvert.toByteArray(ver, dpData, 0); //add: ver + ByteShortConvert.toByteArray(sType, dpData, 2); //add: service type + ByteIntConvert.toByteArray(connectId, dpData, 4); //add: sequence + ByteIntConvert.toByteArray(clientId, dpData, 8); //add: sequence + + ByteIntConvert.toByteArray(lastRead, dpData, 4+8); + //dpData[8]=(byte) ackList.size(); + ByteShortConvert.toByteArray((short) ackList.size(), dpData, 8+8); //add: service type + for(int i=0;i(); + int t=0; + for(int i=0;i 0) { + // MLog.println("删除行 "+row); + String cmd = "iptables -D INPUT " + row; + runCommand(cmd); + } else { + break; + } + } + } + + void setFireWall_linux_tcp() { + cleanTcpTunRule(); + String cmd2 = "iptables -I INPUT -p tcp --dport " + routePort + " -j DROP" + + " -m comment --comment tcptun_fs_server "; + runCommand(cmd2); + + } + + void cleanTcpTunRule() { + while (true) { + int row = getRow("tcptun_fs_server"); + if (row > 0) { + // MLog.println("删除行 "+row); + String cmd = "iptables -D INPUT " + row; + runCommand(cmd); + } else { + break; + } + } + } + + int getRow(String name) { + int row_delect = -1; + String cme_list_rule = "iptables -L -n --line-number"; + // String [] cmd={"netsh","advfirewall set allprofiles state on"}; + Thread errorReadThread = null; + try { + final Process p = Runtime.getRuntime().exec(cme_list_rule, null); + + errorReadThread = new Thread() { + public void run() { + InputStream is = p.getErrorStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line; + try { + line = localBufferedReader.readLine(); + if (line == null) { + break; + } else { + // System.out.println("erroraaa "+line); + } + } catch (IOException e) { + e.printStackTrace(); + // error(); + break; + } + } + } + }; + errorReadThread.start(); + + InputStream is = p.getInputStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line; + try { + line = localBufferedReader.readLine(); + // System.out.println("standaaa "+line); + if (line == null) { + break; + } else { + if (line.contains(name)) { + int index = line.indexOf(" "); + if (index > 0) { + String n = line.substring(0, index); + try { + if (row_delect < 0) { + // System.out.println("standaaabbb + // "+line); + row_delect = Integer.parseInt(n); + } + } catch (Exception e) { + + } + } + } + ; + } + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + + errorReadThread.join(); + p.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + // error(); + } + return row_delect; + } + + void runCommand(String command) { + Thread standReadThread = null; + Thread errorReadThread = null; + try { + final Process p = Runtime.getRuntime().exec(command, null); + standReadThread = new Thread() { + public void run() { + InputStream is = p.getInputStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line; + try { + line = localBufferedReader.readLine(); + // System.out.println("stand "+line); + if (line == null) { + break; + } + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + } + }; + standReadThread.start(); + + errorReadThread = new Thread() { + public void run() { + InputStream is = p.getErrorStream(); + BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line; + try { + line = localBufferedReader.readLine(); + if (line == null) { + break; + } else { + // System.out.println("error "+line); + } + } catch (IOException e) { + e.printStackTrace(); + // error(); + break; + } + } + } + }; + errorReadThread.start(); + standReadThread.join(); + errorReadThread.join(); + p.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + // error(); + } + } + + String readFileData(String path) { + String content = null; + FileInputStream fis = null; + DataInputStream dis = null; + try { + File file = new File(path); + fis = new FileInputStream(file); + dis = new DataInputStream(fis); + byte[] data = new byte[(int) file.length()]; + dis.readFully(data); + content = new String(data, "utf-8"); + } catch (Exception e) { + // e.printStackTrace(); + } finally { + if (dis != null) { + try { + dis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return content; + } + + public int getRoutePort() { + return routePort; + } + +} diff --git a/src/main/java/net/fs/server/MapTunnelProcessor.java b/src/main/java/net/fs/server/MapTunnelProcessor.java new file mode 100755 index 0000000..e540239 --- /dev/null +++ b/src/main/java/net/fs/server/MapTunnelProcessor.java @@ -0,0 +1,152 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.server; + +import com.alibaba.fastjson.JSONObject; +import net.fs.client.Pipe; +import net.fs.rudp.*; +import net.fs.utils.MLog; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + + +public class MapTunnelProcessor implements ConnectionProcessor{ + + Socket dstSocket=null; + + boolean closed=false; + + MapTunnelProcessor pc; + + ConnectionUDP conn; + + + UDPInputStream tis; + + UDPOutputStream tos; + + InputStream sis; + + OutputStream sos; + + public void process(final ConnectionUDP conn){ + this.conn=conn; + pc=this; + Route.es.execute(new Runnable(){ + public void run(){ + process(); + } + }); + } + + + void process(){ + + tis=conn.uis; + tos=conn.uos; + + byte[] headData; + try { + headData = tis.read2(); + String hs=new String(headData,"utf-8"); + JSONObject requestJSon= JSONObject.parseObject(hs); + final int dstPort=requestJSon.getIntValue("dst_port"); + String message=""; + JSONObject responeJSon=new JSONObject(); + int code=Constant.code_failed; + code=Constant.code_success; + responeJSon.put("code", code); + responeJSon.put("message", message); + byte[] responeData=responeJSon.toJSONString().getBytes("utf-8"); + tos.write(responeData, 0, responeData.length); + if(code!=Constant.code_success){ + close(); + return; + } + dstSocket = new Socket("127.0.0.1", dstPort); + dstSocket.setTcpNoDelay(true); + sis=dstSocket.getInputStream(); + sos=dstSocket.getOutputStream(); + + final Pipe p1=new Pipe(); + final Pipe p2=new Pipe(); + + Route.es.execute(new Runnable() { + + public void run() { + try { + p1.pipe(sis, tos,100*1024,p2); + }catch (Exception e) { + //e.printStackTrace(); + }finally{ + close(); + if(p1.getReadedLength()==0){ + MLog.println("数据报错 "+dstPort+" 没有数据返回!"); + } + } + } + + }); + Route.es.execute(new Runnable() { + + public void run() { + try { + p2.pipe(tis,sos,100*1024*1024,conn); + }catch (Exception e) { + //e.printStackTrace(); + }finally{ + close(); + } + } + }); + + + } catch (Exception e2) { + //e2.printStackTrace(); + close(); + } + + + + } + + void close(){ + if(!closed){ + closed=true; + if(sis!=null){ + try { + sis.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + if(sos!=null){ + try { + sos.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + if(tos!=null){ + tos.closeStream_Local(); + } + if(tis!=null){ + tis.closeStream_Local(); + } + if(conn!=null){ + conn.close_local(); + } + if(dstSocket!=null){ + try { + dstSocket.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + } + } + +} diff --git a/src/main/java/net/fs/utils/ByteIntConvert.java b/src/main/java/net/fs/utils/ByteIntConvert.java new file mode 100755 index 0000000..0bbdbfa --- /dev/null +++ b/src/main/java/net/fs/utils/ByteIntConvert.java @@ -0,0 +1,27 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.utils; + + +public class ByteIntConvert { + + public static int toInt(byte[] b,int offset) { + return b[offset + 3] & 0xff | (b[offset + 2] & 0xff) << 8 + | (b[offset + 1] & 0xff) << 16 | (b[offset] & 0xff) << 24; + } + + public static void toByteArray(int n,byte[] buf,int offset) { + buf[offset] = (byte) (n >> 24); + buf[offset + 1] = (byte) (n >> 16); + buf[offset + 2] = (byte) (n >> 8); + buf[offset + 3] = (byte) n; + } + +} + + + + + + + diff --git a/src/main/java/net/fs/utils/ByteShortConvert.java b/src/main/java/net/fs/utils/ByteShortConvert.java new file mode 100755 index 0000000..98e8e0e --- /dev/null +++ b/src/main/java/net/fs/utils/ByteShortConvert.java @@ -0,0 +1,36 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.utils; + +public final class ByteShortConvert { + + public static byte[] toByteArray(short i,byte[] b,int offset) { + b[offset] = (byte) (i >> 8); + b[offset + 1] = (byte) (i >> 0); + return b; + } + + + + public static short toShort(byte[] b,int offset) { + return (short) (((b[offset] << 8) | b[offset + 1] & 0xff)); + } + + //无符号 + public static byte[] toByteArrayUnsigned(int s,byte[] b,int offset) { + b[offset] = (byte) (s >> 8); + b[offset+1] = (byte) (s >> 0); + return b; + } + + //无符号 + public static int toShortUnsigned(byte[] b,int offset) { + int i = 0; + i |= b[offset+0] & 0xFF; + i <<= 8; + i |= b[offset+1] & 0xFF; + return i; + } + + +} diff --git a/src/main/java/net/fs/utils/LogListener.java b/src/main/java/net/fs/utils/LogListener.java new file mode 100755 index 0000000..13dae85 --- /dev/null +++ b/src/main/java/net/fs/utils/LogListener.java @@ -0,0 +1,7 @@ +package net.fs.utils; + +public interface LogListener { + + public void onAppendContent(LogOutputStream los, String text); + +} diff --git a/src/main/java/net/fs/utils/LogOutputStream.java b/src/main/java/net/fs/utils/LogOutputStream.java new file mode 100755 index 0000000..813cadb --- /dev/null +++ b/src/main/java/net/fs/utils/LogOutputStream.java @@ -0,0 +1,49 @@ +package net.fs.utils; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.HashSet; + +public class LogOutputStream extends PrintStream{ + + HashSet listeners=new HashSet(); + + StringBuffer buffer=new StringBuffer(); + + public LogOutputStream(OutputStream out) { + super(out); + } + + @Override + public void write(byte[] buf, int off, int len) { + super.write(buf, off, len); + fireEvent(new String(buf, off, len)); + } + + private void fireEvent(String text){ + if(buffer!=null&&buffer.length()<10000){ + buffer.append(text); + } + for(LogListener listener:listeners){ + listener.onAppendContent(this,text); + } + } + + public void addListener(LogListener listener){ + listeners.add(listener); + } + + public void remvoeListener(LogListener listener){ + listeners.remove(listener); + } + + public StringBuffer getBuffer() { + return buffer; + } + + public void setBuffer(StringBuffer buffer) { + this.buffer = buffer; + } + + +} diff --git a/src/main/java/net/fs/utils/MLog.java b/src/main/java/net/fs/utils/MLog.java new file mode 100755 index 0000000..0e86a23 --- /dev/null +++ b/src/main/java/net/fs/utils/MLog.java @@ -0,0 +1,28 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.utils; + + +public class MLog { + + public static void info(Object str){ + System.out.println(str); + } + +// public static void println(Object str){ +// System.out.println(str); +// } + + public static void println(String str){ + System.out.println(str); + } + +// public static void println(){ +// System.out.println(); +// } +// +// public static void print(String str){ +// System.out.print(str); +// } + +} diff --git a/src/main/java/net/fs/utils/MessageCheck.java b/src/main/java/net/fs/utils/MessageCheck.java new file mode 100755 index 0000000..1c64d5a --- /dev/null +++ b/src/main/java/net/fs/utils/MessageCheck.java @@ -0,0 +1,17 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.utils; + +import java.net.DatagramPacket; + + +public class MessageCheck{ + public static int checkVer(DatagramPacket dp){ + int ver=ByteShortConvert.toShort(dp.getData(), 0); + return ver; + } + public static int checkSType(DatagramPacket dp){ + int sType=ByteShortConvert.toShort(dp.getData(), 2); + return sType; + } +} diff --git a/src/main/java/net/fs/utils/NetStatus.java b/src/main/java/net/fs/utils/NetStatus.java new file mode 100755 index 0000000..b5b718c --- /dev/null +++ b/src/main/java/net/fs/utils/NetStatus.java @@ -0,0 +1,139 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.utils; + +import java.util.Vector; + + +public class NetStatus { + + public long uploadSum; + public long downloadSum; + + Thread mainThread; + + int averageTime; + + Vector speedList; + SpeedUnit currentUnit; + + public int upSpeed=0; + public int downSpeed=0; + + public NetStatus(){ + this(2); + } + + public NetStatus(int averageTime){ + this.averageTime=averageTime; + speedList=new Vector(); + for(int i=0;i1000){ + ////#MLog.println("yyyyyyyyyyy "); + lastTime=System.currentTimeMillis(); + calcuSpeed(); + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // e.printStackTrace(); + break; + } + } + } + }; + mainThread.start(); + } + + public void stop(){ + mainThread.interrupt(); + } + + + public int getUpSpeed() { + return upSpeed; + } + + public void setUpSpeed(int upSpeed) { + this.upSpeed = upSpeed; + } + + public int getDownSpeed() { + return downSpeed; + } + + public void setDownSpeed(int downSpeed) { + this.downSpeed = downSpeed; + } + + + void calcuSpeed(){ + int ds = 0,us=0; + for(SpeedUnit unit:speedList){ + ds+=unit.downSum; + us+=unit.upSum; + } + upSpeed=(int) ((float)us/speedList.size()); + downSpeed=(int)(float)ds/speedList.size(); + + speedList.remove(0); + SpeedUnit unit=new SpeedUnit(); + currentUnit=unit; + speedList.add(unit); + } + + public void addDownload(int sum){ + downloadSum+=sum; + currentUnit.addDown(sum); + } + + public void addUpload(int sum){ + uploadSum+=sum; + currentUnit.addUp(sum); + } + + public void sendAvail(){ + + } + + public void receiveAvail(){ + + } + + public void setUpLimite(int speed){ + + } + + public void setDownLimite(int speed){ + + } +} + + +class SpeedUnit{ + int downSum; + int upSum; + SpeedUnit(){ + + } + + void addUp(int n){ + upSum+=n; + } + + void addDown(int n){ + downSum+=n; + } +} + diff --git a/src/main/java/net/fs/utils/StringRandom.java b/src/main/java/net/fs/utils/StringRandom.java new file mode 100755 index 0000000..228749a --- /dev/null +++ b/src/main/java/net/fs/utils/StringRandom.java @@ -0,0 +1,36 @@ +package net.fs.utils; + +/** + * Created by TD00 on 2017/2/21. + */ +public class StringRandom { + public StringRandom() { + + } + + public static int getRandom(int count) { + return (int) Math.round(Math.random() * (count)); + } + + public static String string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + + public static String getRandomString(int length) { + StringBuffer sb = new StringBuffer(); + int len = string.length(); + for (int i = 0; i < length; i++) { + sb.append(string.charAt(getRandom(len - 1))); + } + return sb.toString(); + } + + private static volatile StringRandom instance = null; + + public static StringRandom getInstance() { + if (instance == null) { + synchronized (StringRandom.class) { + instance = (instance == null ? new StringRandom() : instance); + } + } + return instance; + } +} diff --git a/src/main/java/net/fs/utils/Tools.java b/src/main/java/net/fs/utils/Tools.java new file mode 100755 index 0000000..3fc47e9 --- /dev/null +++ b/src/main/java/net/fs/utils/Tools.java @@ -0,0 +1,78 @@ +// Copyright (c) 2015 D1SM.net + +package net.fs.utils; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.DecimalFormat; + + +public class Tools { + + public static HttpURLConnection getConnection(String urlString) throws Exception{ + URL url = new URL(urlString); + HttpURLConnection conn = null; + if(urlString.startsWith("http://")){ + conn = (HttpURLConnection) url.openConnection(); + }else if(urlString.startsWith("https://")){ + HttpsURLConnection conns=(HttpsURLConnection)url.openConnection(); + conns.setHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + conn=conns; + } + if(conn!=null){ + conn.setConnectTimeout(10*1000); + conn.setReadTimeout(10*1000); + conn.setRequestMethod("POST"); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + } + return conn; + } + + public static String getMD5(String str) { + byte[] source=str.getBytes(); + return getMD5(source); + } + + public static String getMD5(byte[] source) { + String s = null; + char hexDigits[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try + { + java.security.MessageDigest md = java.security.MessageDigest.getInstance( "MD5" ); + md.update( source ); + byte tmp[] = md.digest(); + char str[] = new char[16 * 2]; + int k = 0; + for (int i = 0; i < 16; i++) { + byte byte0 = tmp[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + s = new String(str); + + }catch( Exception e ) + { + e.printStackTrace(); + } + return s; + } + + + public static String getSizeStringKB(long size){ + if(size <= 0) return "0"; + final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" }; + int digitGroups = (int) (Math.log10(size)/Math.log10(1024)); + return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups]; + } + +} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100755 index 0000000..834f129 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,12 @@ +log4j.rootLogger=INFO,fileA,consoleA + +#log4j.appender.fileA=org.apache.log4j.DailyRollingFileAppender +#log4j.appender.fileA.File=./logs/ss-proxy.log +#log4j.appender.fileA.append=true +#log4j.appender.fileA.ImmediateFlush=true +#log4j.appender.fileA.layout=org.apache.log4j.PatternLayout +#log4j.appender.fileA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %L::: %-5p %C - %m%n +# +#log4j.appender.consoleA=org.apache.log4j.ConsoleAppender +#log4j.appender.consoleA.layout=org.apache.log4j.PatternLayout +#log4j.appender.consoleA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} - %m%n \ No newline at end of file diff --git a/src/main/resources/package.xml b/src/main/resources/package.xml new file mode 100755 index 0000000..4351edb --- /dev/null +++ b/src/main/resources/package.xml @@ -0,0 +1,51 @@ + + bin + + + zip + + + + + + + false + lib + false + + + + + + + shell + + + * + + + + conf + conf + + * + + + + + + + *.properties + + + + + + ${project.build.directory} + + + *.jar + + + + \ No newline at end of file diff --git a/winpcap_install.exe b/winpcap_install.exe new file mode 100755 index 0000000..a7f353e Binary files /dev/null and b/winpcap_install.exe differ