6
6
# python doesn't have a definition for this
7
7
IPPROTO_DIVERT = 254
8
8
9
+ # return values from sysctl_set
10
+ SUCCESS = 0
11
+ SAME = 1
12
+ FAILED = - 1
13
+ NONEXIST = - 2
14
+
9
15
10
16
def nonfatal (func , * args ):
11
17
try :
@@ -135,6 +141,48 @@ def _fill_oldctls(prefix):
135
141
raise Fatal ('%r returned no data' % (argv ,))
136
142
137
143
144
+ KERNEL_FLAGS_PATH = '/Library/Preferences/SystemConfiguration/com.apple.Boot'
145
+ KERNEL_FLAGS_NAME = 'Kernel Flags'
146
+ def _defaults_read_kernel_flags ():
147
+ argv = ['defaults' , 'read' , KERNEL_FLAGS_PATH , KERNEL_FLAGS_NAME ]
148
+ debug1 ('>> %s\n ' % ' ' .join (argv ))
149
+ p = ssubprocess .Popen (argv , stdout = ssubprocess .PIPE )
150
+ flagstr = p .stdout .read ().strip ()
151
+ rv = p .wait ()
152
+ if rv :
153
+ raise Fatal ('%r returned %d' % (argv , rv ))
154
+ flags = flagstr and flagstr .split (' ' ) or []
155
+ return flags
156
+
157
+
158
+ def _defaults_write_kernel_flags (flags ):
159
+ flagstr = ' ' .join (flags )
160
+ argv = ['defaults' , 'write' , KERNEL_FLAGS_PATH , KERNEL_FLAGS_NAME ,
161
+ flagstr ]
162
+ debug1 ('>> %s\n ' % ' ' .join (argv ))
163
+ rv = ssubprocess .call (argv )
164
+ if rv :
165
+ raise Fatal ('%r returned %d' (argv , rv ))
166
+ argv = ['plutil' , '-convert' , 'xml1' , KERNEL_FLAGS_PATH + '.plist' ]
167
+ debug1 ('>> %s\n ' % ' ' .join (argv ))
168
+ rv = ssubprocess .call (argv )
169
+ if rv :
170
+ raise Fatal ('%r returned %d' (argv , rv ))
171
+
172
+
173
+
174
+ def defaults_write_kernel_flag (name , val ):
175
+ flags = _defaults_read_kernel_flags ()
176
+ found = 0
177
+ for i in range (len (flags )):
178
+ if flags [i ].startswith ('%s=' % name ):
179
+ found += 1
180
+ flags [i ] = '%s=%s' % (name , val )
181
+ if not found :
182
+ flags .insert (0 , '%s=%s' % (name , val ))
183
+ _defaults_write_kernel_flags (flags )
184
+
185
+
138
186
def _sysctl_set (name , val ):
139
187
argv = ['sysctl' , '-w' , '%s=%s' % (name , val )]
140
188
debug1 ('>> %s\n ' % ' ' .join (argv ))
@@ -150,20 +198,24 @@ def sysctl_set(name, val, permanent=False):
150
198
_fill_oldctls (PREFIX )
151
199
if not (name in _oldctls ):
152
200
debug1 ('>> No such sysctl: %r\n ' % name )
153
- return False
201
+ return NONEXIST
154
202
oldval = _oldctls [name ]
155
- if val != oldval :
156
- rv = _sysctl_set (name , val )
157
- if rv == 0 and permanent :
158
- debug1 ('>> ...saving permanently in /etc/sysctl.conf\n ' )
159
- f = open ('/etc/sysctl.conf' , 'a' )
160
- f .write ('\n '
161
- '# Added by sshuttle\n '
162
- '%s=%s\n ' % (name , val ))
163
- f .close ()
164
- else :
165
- _changedctls .append (name )
166
- return True
203
+ if val == oldval :
204
+ return SAME
205
+
206
+ rv = _sysctl_set (name , val )
207
+ if rv != 0 :
208
+ return FAILED
209
+ if permanent :
210
+ debug1 ('>> ...saving permanently in /etc/sysctl.conf\n ' )
211
+ f = open ('/etc/sysctl.conf' , 'a' )
212
+ f .write ('\n '
213
+ '# Added by sshuttle\n '
214
+ '%s=%s\n ' % (name , val ))
215
+ f .close ()
216
+ else :
217
+ _changedctls .append (name )
218
+ return SUCCESS
167
219
168
220
169
221
def _udp_unpack (p ):
@@ -222,8 +274,8 @@ def do_ipfw(port, dnsport, subnets):
222
274
223
275
if subnets or dnsport :
224
276
sysctl_set ('net.inet.ip.fw.enable' , 1 )
225
- changed = sysctl_set ('net.inet.ip.scopedroute' , 0 , permanent = True )
226
- if changed :
277
+ changeflag = sysctl_set ('net.inet.ip.scopedroute' , 0 , permanent = True )
278
+ if changeflag == SUCCESS :
227
279
log ("\n "
228
280
" WARNING: ONE-TIME NETWORK DISRUPTION:\n "
229
281
" =====================================\n "
@@ -234,6 +286,18 @@ def do_ipfw(port, dnsport, subnets):
234
286
"ethernet port) NOW, then restart sshuttle. The fix is\n "
235
287
"permanent; you only have to do this once.\n \n " )
236
288
sys .exit (1 )
289
+ elif changeflag == FAILED :
290
+ log ('Updating kernel boot flags.\n ' )
291
+ defaults_write_kernel_flag ('net.inet.ip.scopedroute' , 0 )
292
+ log ("\n "
293
+ " YOU MUST REBOOT TO USE SSHUTTLE\n "
294
+ " ===============================\n "
295
+ "sshuttle has changed a MacOS kernel boot-time setting\n "
296
+ "to work around a bug in MacOS 10.7 Lion. You will need\n "
297
+ "to reboot before it takes effect. You only have to\n "
298
+ "do this once.\n \n " )
299
+ sys .exit (1 )
300
+
237
301
238
302
ipfw ('add' , sport , 'check-state' , 'ip' ,
239
303
'from' , 'any' , 'to' , 'any' )
0 commit comments