ÿØÿà JFIF    ÿÛ „ !.%+&8&+/1555$;@;4?.451 4,$,44444444444414444444444444444444444444444444444444ÿÀ  á á" ÿÄ     ÿÄ ?    !1AQaq"2‘¡±ÁðBRbrÑá#‚’¢²3S CñÿÄ   ÿÄ !    !1QAa‘2ÿÚ   ? 5˜Z¯V¦cø)›t/? z¨±>Õ5€¶‹Á¤·¼z¼Ü¬+ñ®v¤¨_ˆR­BFn©—˜ý®ç̝P8gýt·ÉSTŦˆìät?þé¼íìN/Þa)ì–í6ô… Ï¿øÃj´¿KÇü]ÿ ªô¹-eKànëÕHTx}ýSÜ›ÿ ”7Ø×&µ<¦  ¥ÑO¶[Ù¯ä¨ÞÃÿ PZ-¬;#õ|•oaÿ ©CìÞz3˜öː/¤­ñTûIØ}š^ mÓ%ªxˆ¥ÉŸu=Z+ISe¿45™¼u;ú&WØ÷€æßQ™®{|íx*TC“#ZŠìZ§²‹ 6pv…³¿¡äª*áZÐ%ÒOáˆo"x«OHk w±æ+¬V(kMúŸ5Vö«$ ÁrÏbàb57/luR ¸ÑÛj Òµì`Мq­û žICÀÊ•©4€Âcà¨Ï€O´<èÐ:›ù(Ë^L8þ‘ÍÌ#¸Ð_Ì©ÙK(Öz 4¬û+¸;ü’V’84‘¬ÃŽ:[â‡ÔÌáõp¢~§ªlæ£ö{®G>J¼"°‡7¯ÆÉèßû ‹É‹§ÁòÃýâßî ^ƾÙõ‹×óH#«LP½ïX=xÑÍ$|W?•~• îëÔ©ª‹ {ÝT…Kÿ ”hûâá)J*ö˜–ÔU;iÇ€/ ÆþjóZ\ýwØ=Ìm ºèËL9 ýèÆð/¨’¥öo=nË.%Îì ŽÕ¯È|{Oj²ƒE6e/ßdÄõ²Ìâ1O®ò×TsəԸhOMýíMˆ¿¼H˜l²,7Â¥#MF/Úf°Ö½± ¸–dr‹NýÊ íjqx{œÉ ä-È ¦ øÄër¨q°ð †nцýÑÄÆ’mä…n<0È™;ÁÝá¯ÁZƒ7FÀmì­ É&9ˆîéi¶ùN§Y• ÃZãAâ?•‡©‰ , ó¾IŸŠc1 4â&y­&pŠ­6;M À 0¹qç»p.á …ŸÅáK@%6·y6ƒ‰3?”úºŽ‰éX5ªPT §µ!=Mž«Ú½‹ÅgÂSâÉaþÓoö–¯ÁÔìR>5éÿ üs¶ÆUcÌ kÇR ]ÿ ù¬¼«VŽ;Â|‡~¢¦”ÏŰæ {L™Õ°Óv¹ò¸írޡעCÃ!íVÕ {¶»sŒNPg/ "uÕbkm²“$ďå¿é¹§°½æz¯6 †s¿!s–wÚÝ“™Œ °.ûj>·+™Òa…©Œ&rÝÎtÛë긪Ît’LAVp%c Úý[ÄzJ¾ÇàXXç@˜ó<êL]·T˜¾¥1Ó©V‡g´æ½¦Ý@¹óø!_@´ÞâSÁ —S3™•& ]@JHÚý©ZŽ €×æÔr»Áf!‡yÞ4Mv*èÓã_{‘åóUuљØ«Oïé*®EvÑ Œ÷‡U \"㪒ÍK+À 4“M¡ï:0¥5í!'<@î´”>Ç»&Z–ïCCV˜Ì5Šo&îhè.žû |ÓK©h$s6KìŒëã)¹hI¦GïOåóI;ììü#É$Š0…Ææ¥TØ.5­¾gn´ “ÂÖ\:hœ89G)J@„}œ:’Ò{/Š"¦_Æ×7Æ3VÇŠÊa]ÚŒÙ€Ä–=®uÁßâACZƒ§§£ Qnâ:«,×{tyø¬iÛcœÜÄ€H½ÄÍCk´÷šß .W'b¤Íåh]÷€=,Žv×cÚEÚHXJX¶îo¨FÒtèöŸ>ªª6[J®Fµ£sGÁeqõfe\íjÒÐïÄÐGˆe1Ø‹.Ø”‘Ëuø Y­ˆÜ ŽG|zùªüMpDnQWÄ”%JŠ™)â*p@Örš«ÕT2Ð%ˆG#ª„ ·¤!°ŸOTÂT¸aÚ%4&h™LµšØüÐ.F¿²ÐÞ_Ç‚¾ÅÃaÜ÷09Æ q€öy˜v‡85õN÷]¬äѼóS{°_MެúÔ#°Ç¸0åÞè2ëôPcvÆw9®ií1Ä8F™˜à‰´+‰Ik1òÝ7“Ñ×ÒsÝ\x‚h`ÞÑ`ó"|µEcý£n˜h`}GÞ !±ù²Ápü²ß6 0ïi󜵩SÈÇ7˜-ÕURO˜¦´f$ªž-Í6(œ}<„ éc øs]ŽŽ„*—¾ ìdŽ„)méª\¿êÎIg¾ØÞ~I#C/¼¼´EÁÈŽi8“©õådô·>euä ƒ'Ê×लR1ÉJE1ÐAát`t;ÇР%Ý<‡¥„ÍÆ`×Oyó)õiI€ñQaŸ4Ûù\áàaÃÔ¹HÃu¹*k€¦<„e S‡&õÏ B!ŽhüÞ`yj}mªf×\¿ Ç~æ­9‡û\՞Ǖg²1Žû5V7 !àöšm° c`ܬøÇìµÒ'P"?…´Ö,"§^•õލsÔ)6˜sæéÍR¼ ò|Sl”‹7 nPW Gòú÷½§O¯‡„l¡kSÞŒr½PÊ@æ¢pŽ-mÿ #Ÿ˜Àº¶Áä¦;ïÔæ$1££`“Õ>„—·ž)ßð³ñ#Ï Ô$¶œ‰ÊE‹À;÷º ¯«P:Ñ”8–IÊtpÞ3ª“>ê“þës4ò2OÏÕ­±zô†Õ§‰.÷ä¸;¿˜“'œ›žª}«Œ{ª±Ì 9ÔóÞÕ‡0 $íWV3Üì¬ —@kÝ4@¿r¼±½¬™›?øØæ´'Áé®CË3-g$˜ö‡×auÚi´Žp/êÛ æF›Ú2v‹ã¿¿,nB1̨ƃqÞa5͝@&Æû“él÷ \C²½UÍc ¯k×¢U ÖéQå™—-r wô ÞÏ<Ò=&=ÿ Ôê Òêˈt,i—;LîÜ á¸*ÚÃ1$êL•LÍ <É)ýÐà’ ;F™{ƒ™˜€&'}‚ãÄK`¡ÞT@I;®žZóè‚s’7®°›+§O­Åq©é»²9<Ô J ¼9O’HL»Ùïì¸rk¼Ž_ý‘TŸu[²ßÚŒ·ü÷B%¯E ŸÔX5êO´ Ç•€’I0 ÉJX` ñ¹õ%;µŸD‘«´€àwÒ™U ûئžÖö\×®×´8 ½‡ºÐÆÓ§?Àkmœ=;d5*@-ì0F Rªýš[Ü6âö̃ڸr*KA9· u*µæ£?U¸Âêí†8@¦X4 e-ò„0s{ HâUpU?¼mñRa°®a%Ð'tÉ×’\¾ÊÉ]t›h>·(Ë@R¼¡Ãt h}’O÷au<+nT…Ö…MӐ??Óe95 q>í/;&JSû °¯ÊéÞ øƒ*Ã2½Ài&:nôUl=¾¿5eˆ3”ñc|Ú2V”>„»&eE;«ÚäC p¢Û úy 9š[ŒÌx¼擼A&DåÒ¯ˆ¤ÀÌ;"˜ ÏQä¸åhÊ}Ûq«Û0WžÒ|»€ø®öCm5•\ÇÀ§Pe3£]0ÃàLDÉ‰1øªxjgwT‚÷¿LΨK‹›ùs—xˆÜ±µ kæ¸f‰‰ÜGk/LÛØ6d9ò¶ùA{ƒA3š/¬D¬khÓk‰`˜"㯒r¿±Óã jx‡°e}<Ñø\3y:'À•/h½Í€Ç4~g ?Û(¼]v‘ªlKÎâ~?O‚W%{Ì:“'©úNq¾›úo(X’¥¯ˆ nFê{Ç€ü?º'ë ø‹ì Þ09ŒÌç9Æ —ËC`j@ÓÄ(+a‹un¸#ÂꟋ{K`‘ÑÍÍ'à´»/Û,KW;Þ4²þð ï Nm|~fGÏ(…³Ã)«1ö­Õ ¥‡¨©ƒÃ™ü-s=à=U66Ï«Ýc蓦W¹íž®›nÔ%êÇìŒ<#Ü×84ån®Ð ÒåOC` ñânÑs‡¢ç 1õ%Îhì½Ã½® e:ݼUZo™`  ÅZŸŒÊ«ê1ÏÄo$q¹Þ€©ˆhÐÉä¯ñ[!…Ú˜àJ:x2$Íß&PåT£6ç— ‡Í*4Ýšçjÿ ‰É nófÐ ó(L5C•åÆ\rMÒ@ò }y-W}™üýVù—ú¢=Ù”c®‘< M ž ´Phr ¦©TD ‘ù.$´÷O‡‘V2Æò.=IUŒ=ž‡â¬i™aþÓåÙ?òUø'ØÖ•.~* šTŒ!•-×áºTâ®ä#õü'´ eýlYÅÓeÕKÂrT"CÚ@u!Óxƒ{š3€}1¿(r}%«nËamjÑ%ÑNEò v ˜à  σöK³,*º.àzù¨™Ó ÚçâU¦*¿ 9{%Ö¹ njûdaXöb) kÛÆ±ûÓ\°M7ˆÂ=û›ç¿Ã‚­V»Cg–8ÙêE- j)k$º`Ã-ùEýeBÆÇ]c¡°ñty&Òd0nõ'¡W+ƒ*|–øµFa\GQªEAÔp5\Ǽ·¼Ç8·õ -â§Ú[ ‡ uZeÖ 3}×d'+¹:ð+K†Û®s!Ï$úe€<Û”x)1»a­¡LC]¸µík…ÚàA»AYº{†ªS[¦5HÒ7ù --,ísòDØ€èk ÞÀîÜ ò@â( ËNˆë›4ô½•/¦o‡€Û7 ê•ÆêòðÜy'Án½µ á˜ݦ ndeo…[ì¶Ê,¥R³Ä=À±—–ß;£™´ñSâ*g§”ïaið‘Jå~™ÓÞ ß³Õ¢»8x埒²52>AÊb&-÷\7´éÄù€T˜,w;3{ï˜k…à¹ÄqÀ«œ{€\ ˆ¾[´¨јr &Úé„Ívˆ±8†¿]|¬ņ4I×pÞS1ÈÖz‰#Ìv‡G!YNògñ:màTz¢Ý1ô©^O=~ë|5Bã™ç•¼µõ•bÆ@úÕS¬ÈŒ#¬zünrŸ û” Z²•èðV"ÁHÚý©wÝ €7¼Ìu1hÑa3Éä û f$o¿É ™Ú›ÝçnpÒ3äÌ3†Í§,Äï]$‰/pê †«À¼¸e9­Æê_C]žƒ·ý·frÁN«, E=›Çq -‰öŒ:aÏ¿±í&£Í:-} 84‘ÿ eƒQÑeëSsuiA ³g㟥ú£?ÿ ʼn*”“÷aühe:ÊWa@ÒÞk±eØ] F Ô—r.åä˜ @ö¥ªZoÐýYL·¥S²G/‡ñ <~*ZÆ´è>JlòàÛÆ½ÿ 窘ìGN¢:I®KšJp/`íIÁÀõ#Ä-€ö­šµŒoF4|ÆQØÆ@Ì|£Ô…¢À{9˜è½Üó›€ôYÒÎYsið;ís¤€à²ˆ‚4qÉVŒI$ ‰"° æµ8cXGjœˏ¡Aâý•ËÜ¢ûï e·çLx']á"oÅÎê3¯Ç—¹”ó0nå‚âg{Œñ> S´˜îè°g238‚ãköÝfÚd´6Ò€;ò÷±¢™¼›º ¢Æ'¥Ðx'e¬ç ]bÈÆV¢ó‹kýBO ðÊâ$Ÿ!×T 3Mýמ žìٍàÌü‘8÷€àæØ8æ©6‰©L´«…oãpð„~Çk‰!ñ;‹”ÛžÍ àž±z Ÿôû øŸÝužÏ;ÿ #|u6™Þ¬ÚˆÐõA4¶â|ôl|Ê2ŽÇ¤ÝÅÇY.<#Aí.k§hóF‚”Y; M½Ö4hŸ4&›­¿tès´%FìL¥£Ãk‰ÇT¤haÁ¤ÚxfÉ`ÑìË›>i 3t‚:,–+^÷´–{Û–Nxi"x‘Ûg î¨>¥Õ܁ùZH,2Û“:8xÊ¢Çí9.É-Ìâã-=çjwµS˜dütžçwýGòú®®ûº_ˆýx$–¡ãøO EÚÛÏ÷R„×w+3£Á£öUMyR²¹âŒ°š›¸Ñãò9§Ó_Dl+Ùßc›úšGÅÌc†Ž!Ko=¶.‘Îÿ c²(2®V mª.ÿ ¹B›¹å ù„öŸSV>™ü¯$y:G¢Z×àøúdî¹û­·ýÇ´:•c LÍõi_‹ö+ÎæGÊè>OŠ•äž´§Þ{X}¨1ÚTc›»Qþ•êô°t¿OP?eæ~É{5]•ÙR£r5†nZ\ã@ &îJõ ¾àC°þV>fé¥/ü5ñÊIº_é5 ;e­h<@ Ä&æÃëE%;X,ÒãÆÞ`Oò¦kŸm#˜!ÀyÄ¢| óLšò¥Ä` ¶R=|ÈCâh5ò3DˆïF†ðÒ#ÅìÛœ?¸yhBãœí ZxßÎÄhºRK„`Þödvײ™ÀÈÑÒgŒuY w³%†ƒÓzõ ÖÏp‚dH®¦A´ù§»ÓÇMæ~)ˆð‡û:ù&Ä •vGD´À n ݇¼Ö8Fö óáà£~Ë¥x`oK|Ä?fxiØü%pìR>éò+Û±éÎ>núlFŤ'tq8LZÏvÃ?„¡ß±È⽆¯³íü@x|PöUäèØã¡ð‚ŒAìÏ"vÍwóŸÍ{ ý0.z È•Ö{,N¡£¡ŸKÕÙž>Ýœþ ÍÀ°<×EA!Å‚D™IúOÍ¡>ôG}Â` ÍßkÜL™Ž Þð™ {IøF²¹òQ3&!ÃÂÞz.d&Ï-sH¸,Ôõ˜ŽP€ 77ˆÝ¼ÊëÜw =cÕ Ú,ØÐ5ÎYÐ)ì´öœgŒ[¤ßv㙑8心>h]§µháYš£²ºÑ.{Ï7Sð•?´~×SÃKýJÛ˜ ™Íäiúu<µX¶1õ^kâçIÑ£sZ4h>j*ÔšD:4­¿_ ÷¸ Õxæÿ ¸?Mù _•­ÊÐ ä ÷ý ÑwL œ­ïnTkÛUÍN©ë:¦fV ¶ÜÔÜMªÅâA½–¿R×TXš-%iTÊT•‡Ù‚JôϐZxWÑè‰f‰òG º ×Õû2aZ7OU3[“×AT–ÞŒ…-‘¤”Ì ì&(ˆ¿­•ƒkï’:ðY¦W‘ Å)“†‘˜³Åtcø˜ñTÂwÚÇ4|üLÇªí–v- qˆèU qPE.†â‘˜µ Æ,ÐÅs]8¾„oúÑ i>ÜxxÈó)ƒ ´æÁâØ$À‰vžŸf$Ž |ãw;ÀÁIJ»b` {¦Ó¤Ú$©YÀ‘n@Óïž«9J¼êG m¤ ܯ¹ÌW4€ÐÒÅÛ‡#褕Ÿn-?í|с¥÷Ú¹¬'´ÞÜ9ÓK `hê£SÄSà?7—Wí_´…óB›»:=Ãïq`<8ñÓŒÑlú2d¬ê³£hÖ[l|$vÝro~'R®‰§°ñmY ͧäP |PUª¹·:3Œ[Û{Xÿ ºâ@‚W–Äé u‚ ¯´*=íή.pûÒdt @G‰¬ s¸ ëÉücr ÞæÑ¨Ê@>¤¢Ö±. Þ'¯°ÌME[YéïĵÂCå½ Ué©Áû'Ê9%eÔðNU”ë‘ÌsD3/®+UI˜9h.WC”빓$#:pz:YÓ ¿xž* ³$Í +$kñAŠ‹†¢ Uê>¸)_š¬÷©ßAÂÔb9ÇU ¯¾á•9¯ÏÏ÷O÷¼¼Fähal1‰3Ì[Ïr•´UCksNÐ] R‘¸¥H+§Šé†c©vÖÞ0iÓ76s†î!§=ß ¼~Ô'°Ãmäoäš³ªøi1úÉ)³yV8 CLÄØÁ‘WYïi€H6ÖÑiámø^ÈY´°Ñ7¥Û*—Ñ©L«Qƒï—Ùrÿ ›£Ð*š¸ˆL©ˆ$ˆ ÷¾D§9È®«qbqC)–ˆïv´çñsÑVT­Ø, <àïºÀO«Jý·õ àfPìð .wFšir´þ’2_Y *Æ€x\« ì€9š@ Ž|F⇥ˆkZ@hÖÄ0t¿-<“‹qµ¾*ZL¤Ú)&BJpÓF5=$„at*Zš$’ÑtdûÝRI1 2މ$€$I$#‰SÞ’Hë¬ï;Á$¡t$’`<(ñÇt)$‡Ð.Êf¢X’Kt=Éé$‚ˆªè¢oÝëòI%Rgcª÷ŠyI%¡‰ÿ !ñ)´õ $¤ Ô’IIGÿÙ(* OpenVPN module for Augeas Author: Raphael Pinson Author: Justin Akers Reference: http://openvpn.net/index.php/documentation/howto.html Reference: https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage TODO: Inline file support *) module OpenVPN = autoload xfm (************************************************************************ * USEFUL PRIMITIVES *************************************************************************) let eol = Util.eol let indent = Util.indent (* Define separators *) let sep = Util.del_ws_spc (* Define value regexps. Custom simplified ipv6 used instead of Rx.ipv6 as the augeas Travis instances are limited to 2GB of memory. Using 'ipv6_re = Rx.ipv6' consumes an extra 2GB of memory and thus the test is OOM-killed. *) let ipv6_re = /[0-9A-Fa-f:]+/ let ipv4_re = Rx.ipv4 let ip_re = ipv4_re|ipv6_re let num_re = Rx.integer let fn_re = /[^#; \t\n][^#;\n]*[^#; \t\n]|[^#; \t\n]/ let fn_safe_re = /[^#; \t\r\n]+/ let an_re = /[a-z][a-z0-9_-]*/ let hn_re = Rx.hostname let port_re = /[0-9]+/ let host_re = ip_re|hn_re let proto_re = /(tcp|udp)/ let proto_ext_re = /(udp|tcp-client|tcp-server)/ let alg_re = /(none|[A-Za-z][A-Za-z0-9-]+)/ let ipv6_bits_re = ipv6_re . /\/[0-9]+/ (* Define store aliases *) let ip = store ip_re let num = store num_re let filename = store fn_re let filename_safe = store fn_safe_re let hostname = store hn_re let sto_to_dquote = store /[^"\n]+/ (* " Emacs, relax *) let port = store port_re let host = store host_re let proto = store proto_re let proto_ext = store proto_ext_re (* define comments and empty lines *) let comment = Util.comment_generic /[ \t]*[;#][ \t]*/ "# " let comment_or_eol = eol | Util.comment_generic /[ \t]*[;#][ \t]*/ " # " let empty = Util.empty (************************************************************************ * SINGLE VALUES * * - local => IP|hostname * - port => num * - proto => udp|tcp-client|tcp-server * - proto-force => udp|tcp * - mode => p2p|server * - dev => (tun|tap)\d* * - dev-node => filename * - ca => filename * - config => filename * - cert => filename * - key => filename * - dh => filename * - ifconfig-pool-persist => filename * - learn-address => filename * - cipher => [A-Z0-9-]+ * - max-clients => num * - user => alphanum * - group => alphanum * - status => filename * - log => filename * - log-append => filename * - client-config-dir => filename * - verb => num * - mute => num * - fragment => num * - mssfix => num * - connect-retry num * - connect-retry-max num * - connect-timeout num * - http-proxy-timeout num * - max-routes num * - ns-cert-type => "server" * - resolv-retry => "infinite" * - script-security => [0-3] (execve|system)? * - ipchange => command * - topology => type *************************************************************************) let single_host = "local" | "tls-remote" let single_ip = "lladdr" let single_ipv6_bits = "iroute-ipv6" | "server-ipv6" | "ifconfig-ipv6-pool" let single_num = "port" | "max-clients" | "verb" | "mute" | "fragment" | "mssfix" | "connect-retry" | "connect-retry-max" | "connect-timeout" | "http-proxy-timeout" | "resolv-retry" | "lport" | "rport" | "max-routes" | "max-routes-per-client" | "route-metric" | "tun-mtu" | "tun-mtu-extra" | "shaper" | "ping" | "ping-exit" | "ping-restart" | "sndbuf" | "rcvbuf" | "txqueuelen" | "link-mtu" | "nice" | "management-log-cache" | "bcast-buffers" | "tcp-queue-limit" | "server-poll-timeout" | "keysize" | "pkcs11-pin-cache" | "tls-timeout" | "reneg-bytes" | "reneg-pkts" | "reneg-sec" | "hand-window" | "tran-window" let single_fn = "ca" | "cert" | "extra-certs" | "config" | "key" | "dh" | "log" | "log-append" | "client-config-dir" | "dev-node" | "cd" | "chroot" | "writepid" | "client-config-dir" | "tmp-dir" | "replay-persist" | "ca" | "capath" | "pkcs12" | "pkcs11-id" | "askpass" | "tls-export-cert" | "x509-track" let single_an = "user" | "group" | "management-client-user" | "management-client-group" let single_cmd = "ipchange" | "iproute" | "route-up" | "route-pre-down" | "mark" | "up" | "down" | "setcon" | "echo" | "client-connect" | "client-disconnect" | "learn-address" | "tls-verify" let single_entry (kw:regexp) (re:regexp) = [ key kw . sep . store re . comment_or_eol ] let single_opt_entry (kw:regexp) (re:regexp) = [ key kw . (sep . store re)? .comment_or_eol ] let single = single_entry single_num num_re | single_entry single_fn fn_re | single_entry single_an an_re | single_entry single_host host_re | single_entry single_ip ip_re | single_entry single_ipv6_bits ipv6_bits_re | single_entry single_cmd fn_re | single_entry "proto" proto_ext_re | single_entry "proto-force" proto_re | single_entry "mode" /(p2p|server)/ | single_entry "dev" /(tun|tap)[0-9]*|null/ | single_entry "dev-type" /(tun|tap)/ | single_entry "topology" /(net30|p2p|subnet)/ | single_entry "cipher" alg_re | single_entry "auth" alg_re | single_entry "resolv-retry" "infinite" | single_entry "script-security" /[0-3]( execve| system)?/ | single_entry "route-gateway" (host_re|/dhcp/) | single_entry "mtu-disc" /(no|maybe|yes)/ | single_entry "remap-usr1" /SIG(HUP|TERM)/ | single_entry "socket-flags" /(TCP_NODELAY)/ | single_entry "auth-retry" /(none|nointeract|interact)/ | single_entry "tls-version-max" Rx.decimal | single_entry "verify-hash" /([A-Za-z0-9]{2}:)+[A-Za-z0-9]{2}/ | single_entry "pkcs11-cert-private" /[01]/ | single_entry "pkcs11-protected-authentication" /[01]/ | single_entry "pkcs11-private-mode" /[A-Za-z0-9]+/ | single_entry "key-method" /[12]/ | single_entry "ns-cert-type" /(client|server)/ | single_entry "remote-cert-tls" /(client|server)/ let single_opt = single_opt_entry "comp-lzo" /(yes|no|adaptive)/ | single_opt_entry "syslog" fn_re | single_opt_entry "daemon" fn_re | single_opt_entry "auth-user-pass" fn_re | single_opt_entry "explicit-exit-notify" num_re | single_opt_entry "engine" fn_re (************************************************************************ * DOUBLE VALUES *************************************************************************) let double_entry (kw:regexp) (a:string) (aval:regexp) (b:string) (bval:regexp) = [ key kw . sep . [ label a . store aval ] . sep . [ label b . store bval ] . comment_or_eol ] let double_secopt_entry (kw:regexp) (a:string) (aval:regexp) (b:string) (bval:regexp) = [ key kw . sep . [ label a . store aval ] . (sep . [ label b . store bval ])? . comment_or_eol ] let double = double_entry "keepalive" "ping" num_re "timeout" num_re | double_entry "hash-size" "real" num_re "virtual" num_re | double_entry "ifconfig" "local" ip_re "remote" ip_re | double_entry "connect-freq" "num" num_re "sec" num_re | double_entry "verify-x509-name" "name" hn_re "type" /(subject|name|name-prefix)/ | double_entry "ifconfig-ipv6" "address" ipv6_bits_re "remote" ipv6_re | double_entry "ifconfig-ipv6-push" "address" ipv6_bits_re "remote" ipv6_re | double_secopt_entry "iroute" "local" ip_re "netmask" ip_re | double_secopt_entry "stale-routes-check" "age" num_re "interval" num_re | double_secopt_entry "ifconfig-pool-persist" "file" fn_safe_re "seconds" num_re | double_secopt_entry "secret" "file" fn_safe_re "direction" /[01]/ | double_secopt_entry "prng" "algorithm" alg_re "nsl" num_re | double_secopt_entry "replay-window" "window-size" num_re "seconds" num_re (************************************************************************ * FLAGS *************************************************************************) let flag_words = "client-to-client" | "duplicate-cn" | "persist-key" | "persist-tun" | "client" | "remote-random" | "nobind" | "mute-replay-warnings" | "http-proxy-retry" | "socks-proxy-retry" | "remote-random-hostname" | "show-proxy-settings" | "float" | "bind" | "nobind" | "tun-ipv6" | "ifconfig-noexec" | "ifconfig-nowarn" | "route-noexec" | "route-nopull" | "allow-pull-fqdn" | "mtu-test" | "ping-timer-rem" | "persist-tun" | "persist-local-ip" | "persist-remote-ip" | "mlock" | "up-delay" | "down-pre" | "up-restart" | "disable-occ" | "errors-to-stderr" | "passtos" | "suppress-timestamps" | "fast-io" | "multihome" | "comp-noadapt" | "management-client" | "management-query-passwords" | "management-query-proxy" | "management-query-remote" | "management-forget-disconnect" | "management-hold" | "management-signal" | "management-up-down" | "management-client-auth" | "management-client-pf" | "push-reset" | "push-peer-info" | "disable" | "ifconfig-pool-linear" | "client-to-client" | "duplicate-cn" | "ccd-exclusive" | "tcp-nodelay" | "opt-verify" | "auth-user-pass-optional" | "client-cert-not-required" | "username-as-common-name" | "pull" | "key-direction" | "no-replay" | "mute-replay-warnings" | "no-iv" | "use-prediction-resistance" | "test-crypto" | "tls-server" | "tls-client" | "pkcs11-id-management" | "single-session" | "tls-exit" | "auth-nocache" | "show-ciphers" | "show-digests" | "show-tls" | "show-engines" | "genkey" | "mktun" | "rmtun" let flag_entry (kw:regexp) = [ key kw . comment_or_eol ] let flag = flag_entry flag_words (************************************************************************ * OTHER FIELDS * * - server => IP IP [nopool] * - server-bridge => IP IP IP IP * - route => host host [host [num]] * - push => "string" * - tls-auth => filename [01] * - remote => hostname/IP [num] [(tcp|udp)] * - management => IP num filename * - http-proxy => host port [filename|keyword] [method] * - http-proxy-option => (VERSION decimal|AGENT string) * ... * and many others * *************************************************************************) let server = [ key "server" . sep . [ label "address" . ip ] . sep . [ label "netmask" . ip ] . (sep . [ key "nopool" ]) ? . comment_or_eol ] let server_bridge = let ip_params = [ label "address" . ip ] . sep . [ label "netmask" . ip ] . sep . [ label "start" . ip ] . sep . [ label "end" . ip ] in [ key "server-bridge" . sep . (ip_params|store /(nogw)/) . comment_or_eol ] let route = let route_net_kw = store (/(vpn_gateway|net_gateway|remote_host)/|host_re) in [ key "route" . sep . [ label "address" . route_net_kw ] . (sep . [ label "netmask" . store (ip_re|/default/) ] . (sep . [ label "gateway" . route_net_kw ] . (sep . [ label "metric" . store (/default/|num_re)] )? )? )? . comment_or_eol ] let route_ipv6 = let route_net_re = /(vpn_gateway|net_gateway|remote_host)/ in [ key "route-ipv6" . sep . [ label "network" . store (route_net_re|ipv6_bits_re) ] . (sep . [ label "gateway" . store (route_net_re|ipv6_re) ] . (sep . [ label "metric" . store (/default/|num_re)] )? )? . comment_or_eol ] let push = [ key "push" . sep . Quote.do_dquote sto_to_dquote . comment_or_eol ] let tls_auth = [ key "tls-auth" . sep . [ label "key" . filename ] . sep . [ label "is_client" . store /[01]/ ] . comment_or_eol ] let remote = [ key "remote" . sep . [ label "server" . host ] . (sep . [label "port" . port] . (sep . [label "proto" . proto]) ? ) ? . comment_or_eol ] let http_proxy = let auth_method_re = /(none|basic|ntlm)/ in let auth_method = store auth_method_re in [ key "http-proxy" . sep . [ label "server" . host ] . sep . [ label "port" . port ] . (sep . [ label "auth" . filename_safe ] . (sep . [ label "auth-method" . auth_method ]) ? )? . comment_or_eol ] let http_proxy_option = [ key "http-proxy-option" . sep . [ label "option" . store /(VERSION|AGENT)/ ] . sep . [ label "value" . filename ] . comment_or_eol ] let socks_proxy = [ key "socks-proxy" . sep . [ label "server" . host ] . (sep . [ label "port" . port ] . (sep . [ label "auth" . filename_safe ])? )? . comment_or_eol ] let port_share = [ key "port-share" . sep . [ label "host" . host ] . sep . [ label "port" . port ] . (sep . [ label "dir" . filename ])? . comment_or_eol ] let route_delay = [ key "route-delay" . (sep . [ label "seconds" . num ] . (sep . [ label "win-seconds" . num ] ) ? )? . comment_or_eol ] let inetd = [ key "inetd" . (sep . [label "mode" . store /(wait|nowait)/ ] . (sep . [ label "progname" . filename ] ) ? )? . comment_or_eol ] let inactive = [ key "inactive" . sep . [ label "seconds" . num ] . (sep . [ label "bytes" . num ] ) ? . comment_or_eol ] let client_nat = [ key "client-nat" . sep . [ label "type" . store /(snat|dnat)/ ] . sep . [ label "network" . ip ] . sep . [ label "netmask" . ip ] . sep . [ label "alias" . ip ] . comment_or_eol ] let status = [ key "status" . sep . [ label "file" . filename_safe ] . (sep . [ label "repeat-seconds" . num ]) ? . comment_or_eol ] let plugin = [ key "plugin" . sep . [ label "file" . filename_safe ] . (sep . [ label "init-string" . filename ]) ? . comment_or_eol ] let management = [ key "management" . sep . [ label "server" . ip ] . sep . [ label "port" . port ] . (sep . [ label "pwfile" . filename ] ) ? . comment_or_eol ] let auth_user_pass_verify = [ key "auth-user-pass-verify" . sep . [ Quote.quote_spaces (label "command") ] . sep . [ label "method" . store /via-(env|file)/ ] . comment_or_eol ] let static_challenge = [ key "static-challenge" . sep . [ Quote.quote_spaces (label "text") ] . sep . [ label "echo" . store /[01]/ ] . comment_or_eol ] let cryptoapicert = [ key "cryptoapicert" . sep . Quote.dquote . [ key /[A-Z]+/ . Sep.colon . store /[A-Za-z _-]+/ ] . Quote.dquote . comment_or_eol ] let setenv = let envvar = /[^#;\/ \t\n][A-Za-z0-9_-]+/ in [ key ("setenv"|"setenv-safe") . sep . [ key envvar . sep . store fn_re ] . comment_or_eol ] let redirect = let redirect_flag = /(local|autolocal|def1|bypass-dhcp|bypass-dns|block-local)/ in let redirect_key = "redirect-gateway" | "redirect-private" in [ key redirect_key . (sep . [ label "flag" . store redirect_flag ] ) + . comment_or_eol ] let tls_cipher = let ciphername = /[A-Za-z0-9!_-]+/ in [ key "tls-cipher" . sep . [label "cipher" . store ciphername] . (Sep.colon . [label "cipher" . store ciphername])* . comment_or_eol ] let remote_cert_ku = let usage = [label "usage" . store /[A-Za-z0-9]{1,2}/] in [ key "remote-cert-ku" . sep . usage . (sep . usage)* . comment_or_eol ] (* FIXME: Surely there's a nicer way to do this *) let remote_cert_eku = let oid = [label "oid" . store /[0-9]+\.([0-9]+\.)*[0-9]+/] in let symbolic = [Quote.do_quote_opt (label "symbol" . store /[A-Za-z0-9][A-Za-z0-9 _-]*[A-Za-z0-9]/)] in [ key "remote-cert-eku" . sep . (oid|symbolic) . comment_or_eol ] let status_version = [ key "status-version" . (sep . num) ? . comment_or_eol ] let ifconfig_pool = [ key "ifconfig-pool" . sep . [ label "start" . ip ] . sep . [ label "end" . ip ] . (sep . [ label "netmask" . ip ])? . comment_or_eol ] let ifconfig_push = [ key "ifconfig-push" . sep . [ label "local" . ip ] . sep . [ label "remote-netmask" . ip ] . (sep . [ label "alias" . store /[A-Za-z0-9_-]+/ ] )? . comment_or_eol ] let ignore_unknown_option = [ key "ignore-unknown-option" . (sep . [ label "opt" . store /[A-Za-z0-9_-]+/ ] ) + . comment_or_eol ] let tls_version_min = [ key "tls-version-min" . sep . store Rx.decimal . (sep . [ key "or-highest" ]) ? . comment_or_eol ] let crl_verify = [ key "crl-verify" . sep . filename_safe . (sep . [ key "dir" ]) ? . comment_or_eol ] let x509_username_field = let fieldname = /[A-Za-z0-9_-]+/ in let extfield = ([key /ext/ . Sep.colon . store fieldname]) in let subjfield = ([label "subj" . store fieldname]) in [ key "x509-username-field" . sep . (extfield|subjfield) . comment_or_eol ] let other = server | server_bridge | route | push | tls_auth | remote | http_proxy | http_proxy_option | socks_proxy | management | route_delay | client_nat | redirect | inactive | setenv | inetd | status | status_version | plugin | ifconfig_pool | ifconfig_push | ignore_unknown_option | auth_user_pass_verify | port_share | static_challenge | tls_version_min | tls_cipher | cryptoapicert | x509_username_field | remote_cert_ku | remote_cert_eku | crl_verify | route_ipv6 (************************************************************************ * LENS & FILTER *************************************************************************) let lns = ( comment | empty | single | single_opt | double | flag | other )* let filter = (incl "/etc/openvpn/client.conf") . (incl "/etc/openvpn/server.conf") let xfm = transform lns filter