What is important to understand is that the . is a dot_match_all that matches everything (except newlines) by default. So, (.*) is greedy by nature and wants to match as much as it can.
I think what you may be looking for is changing (.*) to (.+?) to make it lazy. This way, once it matches up to < followed by / then t, then d, then >, it will stop:
preg_match('|<td class="details_header" width="100px" valign="top" nowrap="nowrap">prod</td><td>color=red[/color]</td>|ims', $content, $match1);
And of course, you will want to use match1[1] for your desired captured result.
EDIT - On a side note, I find $match1 to be a strange variable name, as I would simply use $match and thus access $match[1]... but that's just my opinion.